carconnectivity-plugin-database 0.1a11__tar.gz → 0.1a14__tar.gz
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.1a11/src/carconnectivity_plugin_database.egg-info → carconnectivity_plugin_database-0.1a14}/PKG-INFO +2 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/pyproject.toml +1 -1
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14/src/carconnectivity_plugin_database.egg-info}/PKG-INFO +2 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugin_database.egg-info/SOURCES.txt +3 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugin_database.egg-info/requires.txt +1 -1
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/_version.py +3 -3
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/charging_agent.py +132 -24
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/drive_state_agent.py +36 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/trip_agent.py +1 -1
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/__init__.py +4 -1
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/charging_power.py +7 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/charging_rate.py +7 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/charging_session.py +18 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/charging_state.py +6 -2
- carconnectivity_plugin_database-0.1a14/src/carconnectivity_plugins/database/model/charging_station.py +66 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/climatization_state.py +6 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/connection_state.py +6 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/drive.py +7 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/drive_level.py +6 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/drive_range.py +6 -2
- carconnectivity_plugin_database-0.1a14/src/carconnectivity_plugins/database/model/drive_range_full.py +53 -0
- carconnectivity_plugin_database-0.1a14/src/carconnectivity_plugins/database/model/location.py +85 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/outside_temperature.py +6 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/state.py +6 -2
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/trip.py +13 -4
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/vehicle.py +7 -1
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.flake8 +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/dependabot.yml +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/workflows/build.yml +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/workflows/build_and_publish.yml +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.github/workflows/codeql-analysis.yml +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/.gitignore +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/LICENSE +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/Makefile +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/README.md +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/doc/Config.md +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/setup.cfg +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/setup_requirements.txt +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_database/__init__.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_database/carconnectivity_database_base.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugin_database.egg-info/dependency_links.txt +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugin_database.egg-info/entry_points.txt +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugin_database.egg-info/top_level.txt +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/__init__.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/base_agent.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/climatization_agent.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/agents/state_agent.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/alembic.ini +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/base.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/carconnectivity_schema/README +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/carconnectivity_schema/__init__.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/carconnectivity_schema/env.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/carconnectivity_schema/script.py.mako +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/carconnectivity_schema/versions/__init__.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/datetime_decorator.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/migrations.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/tag.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/model/timedelta_decorator.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/plugin.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/ui/plugin_ui.py +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/src/carconnectivity_plugins/database/ui/templates/database/status.html +0 -0
- {carconnectivity_plugin_database-0.1a11 → carconnectivity_plugin_database-0.1a14}/test/integration_test/carConnectivity.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carconnectivity-plugin-database
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1a14
|
|
4
4
|
Summary: CarConnectivity plugin for storing data to Databases
|
|
5
5
|
Author: Till Steinbach
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Home Automation
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: carconnectivity>=0.
|
|
22
|
+
Requires-Dist: carconnectivity>=0.10
|
|
23
23
|
Requires-Dist: sqlalchemy~=2.0.45
|
|
24
24
|
Requires-Dist: psycopg2-binary~=2.9.11
|
|
25
25
|
Requires-Dist: alembic~=1.17.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carconnectivity-plugin-database
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1a14
|
|
4
4
|
Summary: CarConnectivity plugin for storing data to Databases
|
|
5
5
|
Author: Till Steinbach
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Home Automation
|
|
|
19
19
|
Requires-Python: >=3.9
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: carconnectivity>=0.
|
|
22
|
+
Requires-Dist: carconnectivity>=0.10
|
|
23
23
|
Requires-Dist: sqlalchemy~=2.0.45
|
|
24
24
|
Requires-Dist: psycopg2-binary~=2.9.11
|
|
25
25
|
Requires-Dist: alembic~=1.17.2
|
|
@@ -36,12 +36,15 @@ src/carconnectivity_plugins/database/model/charging_power.py
|
|
|
36
36
|
src/carconnectivity_plugins/database/model/charging_rate.py
|
|
37
37
|
src/carconnectivity_plugins/database/model/charging_session.py
|
|
38
38
|
src/carconnectivity_plugins/database/model/charging_state.py
|
|
39
|
+
src/carconnectivity_plugins/database/model/charging_station.py
|
|
39
40
|
src/carconnectivity_plugins/database/model/climatization_state.py
|
|
40
41
|
src/carconnectivity_plugins/database/model/connection_state.py
|
|
41
42
|
src/carconnectivity_plugins/database/model/datetime_decorator.py
|
|
42
43
|
src/carconnectivity_plugins/database/model/drive.py
|
|
43
44
|
src/carconnectivity_plugins/database/model/drive_level.py
|
|
44
45
|
src/carconnectivity_plugins/database/model/drive_range.py
|
|
46
|
+
src/carconnectivity_plugins/database/model/drive_range_full.py
|
|
47
|
+
src/carconnectivity_plugins/database/model/location.py
|
|
45
48
|
src/carconnectivity_plugins/database/model/migrations.py
|
|
46
49
|
src/carconnectivity_plugins/database/model/outside_temperature.py
|
|
47
50
|
src/carconnectivity_plugins/database/model/state.py
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1, '
|
|
31
|
+
__version__ = version = '0.1a14'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 'a14')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g0e0346a6f'
|
|
@@ -2,8 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
+
from datetime import timedelta
|
|
5
6
|
|
|
6
|
-
from sqlalchemy import and_
|
|
7
7
|
from sqlalchemy.exc import DatabaseError
|
|
8
8
|
|
|
9
9
|
from carconnectivity.observable import Observable
|
|
@@ -17,6 +17,8 @@ from carconnectivity_plugins.database.model.charging_state import ChargingState
|
|
|
17
17
|
from carconnectivity_plugins.database.model.charging_rate import ChargingRate
|
|
18
18
|
from carconnectivity_plugins.database.model.charging_power import ChargingPower
|
|
19
19
|
from carconnectivity_plugins.database.model.charging_session import ChargingSession
|
|
20
|
+
from carconnectivity_plugins.database.model.location import Location
|
|
21
|
+
from carconnectivity_plugins.database.model.charging_station import ChargingStation
|
|
20
22
|
|
|
21
23
|
if TYPE_CHECKING:
|
|
22
24
|
from typing import Optional
|
|
@@ -40,8 +42,7 @@ class ChargingAgent(BaseAgent):
|
|
|
40
42
|
self.session: Session = session
|
|
41
43
|
self.vehicle: Vehicle = vehicle
|
|
42
44
|
|
|
43
|
-
self.last_charging_session: Optional[ChargingSession] = session.query(ChargingSession).filter(
|
|
44
|
-
ChargingSession.session_start_date.is_not(None))) \
|
|
45
|
+
self.last_charging_session: Optional[ChargingSession] = session.query(ChargingSession).filter(ChargingSession.vehicle == vehicle) \
|
|
45
46
|
.order_by(ChargingSession.session_start_date.desc()).first()
|
|
46
47
|
self.carconnectivity_last_charging_state: Optional[Charging.ChargingState] = vehicle.carconnectivity_vehicle.charging.state.value
|
|
47
48
|
self.carconnectivity_last_connector_state: Optional[ChargingConnector.ChargingConnectorConnectionState] = vehicle.carconnectivity_vehicle.charging\
|
|
@@ -49,7 +50,12 @@ class ChargingAgent(BaseAgent):
|
|
|
49
50
|
self.carconnectivity_last_connector_lock_state: Optional[ChargingConnector.ChargingConnectorLockState] = vehicle.carconnectivity_vehicle.charging\
|
|
50
51
|
.connector.lock_state.value
|
|
51
52
|
if self.last_charging_session is not None and not self.last_charging_session.is_closed():
|
|
52
|
-
if vehicle.carconnectivity_vehicle.charging.state.value in (Charging.ChargingState.CHARGING, Charging.ChargingState.CONSERVATION)
|
|
53
|
+
if vehicle.carconnectivity_vehicle.charging.state.value in (Charging.ChargingState.CHARGING, Charging.ChargingState.CONSERVATION) \
|
|
54
|
+
or (vehicle.carconnectivity_vehicle.charging.connector.connection_state.enabled
|
|
55
|
+
and vehicle.carconnectivity_vehicle.charging.connector.connection_state.value ==
|
|
56
|
+
ChargingConnector.ChargingConnectorConnectionState.CONNECTED) \
|
|
57
|
+
or (vehicle.carconnectivity_vehicle.charging.connector.lock_state.enabled
|
|
58
|
+
and vehicle.carconnectivity_vehicle.charging.connector.lock_state.value == ChargingConnector.ChargingConnectorLockState.LOCKED):
|
|
53
59
|
LOG.info("Last charging session for vehicle %s is still open during startup, will continue this session", vehicle.vin)
|
|
54
60
|
else:
|
|
55
61
|
LOG.info("Last charging session for vehicle %s is still open during startup, but we are not charging, ignoring it", vehicle.vin)
|
|
@@ -118,24 +124,47 @@ class ChargingAgent(BaseAgent):
|
|
|
118
124
|
if element.value in (Charging.ChargingState.CHARGING, Charging.ChargingState.CONSERVATION) \
|
|
119
125
|
and self.carconnectivity_last_charging_state not in (Charging.ChargingState.CHARGING, Charging.ChargingState.CONSERVATION):
|
|
120
126
|
if self.last_charging_session is None or self.last_charging_session.is_closed():
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
# check that we are not resuming an old session
|
|
128
|
+
allowed_interrupt: timedelta = timedelta(hours=24)
|
|
129
|
+
# we allow longer CONSERVATION within the session
|
|
130
|
+
if element.value == Charging.ChargingState.CONSERVATION:
|
|
131
|
+
allowed_interrupt = timedelta(hours=300)
|
|
132
|
+
# We can reuse the session if the vehicle was connected and not disconnected in the meantime
|
|
133
|
+
# And the session end date was not set or is within the allowed interrupt time
|
|
134
|
+
if self.last_charging_session is not None \
|
|
135
|
+
and self.last_charging_session.was_connected() and not self.last_charging_session.was_disconnected() \
|
|
136
|
+
and (self.last_charging_session.session_end_date is None or element.last_changed is None
|
|
137
|
+
or self.last_charging_session.session_end_date > (element.last_changed - allowed_interrupt)):
|
|
138
|
+
LOG.debug("Continuing existing charging session for vehicle %s", self.vehicle.vin)
|
|
139
|
+
try:
|
|
140
|
+
self.last_charging_session.session_end_date = None
|
|
141
|
+
self.last_charging_session.end_level = None
|
|
142
|
+
except DatabaseError as err:
|
|
143
|
+
self.session.rollback()
|
|
144
|
+
LOG.error('DatabaseError while updating charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
145
|
+
else:
|
|
146
|
+
LOG.info("Starting new charging session for vehicle %s", self.vehicle.vin)
|
|
147
|
+
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, session_start_date=element.last_changed)
|
|
148
|
+
try:
|
|
149
|
+
self.session.add(new_session)
|
|
150
|
+
LOG.debug('Added new charging session for vehicle %s to database', self.vehicle.vin)
|
|
151
|
+
self._update_session_odometer(new_session)
|
|
152
|
+
self._update_session_position(new_session)
|
|
153
|
+
self._update_session_charging_type(new_session)
|
|
154
|
+
self.last_charging_session = new_session
|
|
155
|
+
except DatabaseError as err:
|
|
156
|
+
self.session.rollback()
|
|
157
|
+
LOG.error('DatabaseError while adding charging session for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
131
158
|
else:
|
|
132
159
|
if self.last_charging_session.was_started():
|
|
133
160
|
LOG.debug("Continuing existing charging session for vehicle %s", self.vehicle.vin)
|
|
134
161
|
else:
|
|
135
162
|
LOG.debug("Starting charging in existing charging session for vehicle %s", self.vehicle.vin)
|
|
136
163
|
try:
|
|
137
|
-
self.last_charging_session.session_start_date = element.
|
|
164
|
+
self.last_charging_session.session_start_date = element.last_changed
|
|
138
165
|
self._update_session_odometer(self.last_charging_session)
|
|
166
|
+
self._update_session_position(self.last_charging_session)
|
|
167
|
+
self._update_session_charging_type(self.last_charging_session)
|
|
139
168
|
except DatabaseError as err:
|
|
140
169
|
self.session.rollback()
|
|
141
170
|
LOG.error('DatabaseError while starting charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
@@ -153,7 +182,7 @@ class ChargingAgent(BaseAgent):
|
|
|
153
182
|
if self.last_charging_session is not None and not self.last_charging_session.was_ended():
|
|
154
183
|
LOG.info("Ending charging session for vehicle %s", self.vehicle.vin)
|
|
155
184
|
try:
|
|
156
|
-
self.last_charging_session.session_end_date = element.
|
|
185
|
+
self.last_charging_session.session_end_date = element.last_changed
|
|
157
186
|
except DatabaseError as err:
|
|
158
187
|
self.session.rollback()
|
|
159
188
|
LOG.error('DatabaseError while ending charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
@@ -230,11 +259,12 @@ class ChargingAgent(BaseAgent):
|
|
|
230
259
|
if element.value == ChargingConnector.ChargingConnectorConnectionState.CONNECTED \
|
|
231
260
|
and self.carconnectivity_last_connector_state != ChargingConnector.ChargingConnectorConnectionState.CONNECTED:
|
|
232
261
|
if self.last_charging_session is None or self.last_charging_session.is_closed():
|
|
233
|
-
LOG.info("Starting new charging session for vehicle %s", self.vehicle.vin)
|
|
234
|
-
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_connected_date=element.
|
|
262
|
+
LOG.info("Starting new charging session for vehicle %s due to connector connected state", self.vehicle.vin)
|
|
263
|
+
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_connected_date=element.last_changed)
|
|
235
264
|
try:
|
|
236
265
|
self.session.add(new_session)
|
|
237
266
|
self._update_session_odometer(new_session)
|
|
267
|
+
self._update_session_position(new_session)
|
|
238
268
|
LOG.debug('Added new charging session for vehicle %s to database', self.vehicle.vin)
|
|
239
269
|
self.last_charging_session = new_session
|
|
240
270
|
except DatabaseError as err:
|
|
@@ -243,8 +273,9 @@ class ChargingAgent(BaseAgent):
|
|
|
243
273
|
elif not self.last_charging_session.was_connected():
|
|
244
274
|
LOG.debug("Continuing existing charging session for vehicle %s, writing connected date", self.vehicle.vin)
|
|
245
275
|
try:
|
|
246
|
-
self.last_charging_session.plug_connected_date = element.
|
|
276
|
+
self.last_charging_session.plug_connected_date = element.last_changed
|
|
247
277
|
self._update_session_odometer(self.last_charging_session)
|
|
278
|
+
self._update_session_position(self.last_charging_session)
|
|
248
279
|
except DatabaseError as err:
|
|
249
280
|
self.session.rollback()
|
|
250
281
|
LOG.error('DatabaseError while starting charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
@@ -253,10 +284,32 @@ class ChargingAgent(BaseAgent):
|
|
|
253
284
|
if self.last_charging_session is not None and not self.last_charging_session.was_disconnected():
|
|
254
285
|
LOG.info("Writing plug disconnected date for charging session of vehicle %s", self.vehicle.vin)
|
|
255
286
|
try:
|
|
256
|
-
self.last_charging_session.plug_disconnected_date = element.
|
|
287
|
+
self.last_charging_session.plug_disconnected_date = element.last_changed
|
|
257
288
|
except DatabaseError as err:
|
|
258
289
|
self.session.rollback()
|
|
259
290
|
LOG.error('DatabaseError while ending charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
291
|
+
# Create charging session when connected at startup
|
|
292
|
+
elif element.value == ChargingConnector.ChargingConnectorConnectionState.CONNECTED \
|
|
293
|
+
and self.carconnectivity_last_connector_state == ChargingConnector.ChargingConnectorConnectionState.CONNECTED:
|
|
294
|
+
if self.last_charging_session is None or self.last_charging_session.is_closed():
|
|
295
|
+
LOG.info("Starting new charging session for vehicle %s due to connector connected state", self.vehicle.vin)
|
|
296
|
+
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_connected_date=element.last_changed)
|
|
297
|
+
try:
|
|
298
|
+
self.session.add(new_session)
|
|
299
|
+
self._update_session_odometer(new_session)
|
|
300
|
+
self._update_session_position(new_session)
|
|
301
|
+
LOG.debug('Added new charging session for vehicle %s to database', self.vehicle.vin)
|
|
302
|
+
self.last_charging_session = new_session
|
|
303
|
+
except DatabaseError as err:
|
|
304
|
+
self.session.rollback()
|
|
305
|
+
LOG.error('DatabaseError while adding charging session for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
306
|
+
elif self.last_charging_session is not None and not self.last_charging_session.was_connected():
|
|
307
|
+
try:
|
|
308
|
+
self.last_charging_session.plug_connected_date = element.last_changed
|
|
309
|
+
LOG.info("Writing plug connected date for charging session of vehicle %s", self.vehicle.vin)
|
|
310
|
+
except DatabaseError as err:
|
|
311
|
+
self.session.rollback()
|
|
312
|
+
LOG.error('DatabaseError while changing charging session for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
260
313
|
self.carconnectivity_last_connector_state = element.value
|
|
261
314
|
|
|
262
315
|
def __on_connector_lock_state_change(self, element: EnumAttribute[ChargingConnector.ChargingConnectorLockState], flags: Observable.ObserverEvent) -> None:
|
|
@@ -270,11 +323,12 @@ class ChargingAgent(BaseAgent):
|
|
|
270
323
|
if element.value == ChargingConnector.ChargingConnectorLockState.LOCKED \
|
|
271
324
|
and self.carconnectivity_last_connector_lock_state != ChargingConnector.ChargingConnectorLockState.LOCKED:
|
|
272
325
|
if self.last_charging_session is None or self.last_charging_session.is_closed():
|
|
273
|
-
LOG.info("Starting new charging session for vehicle %s", self.vehicle.vin)
|
|
274
|
-
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_locked_date=element.
|
|
326
|
+
LOG.info("Starting new charging session for vehicle %s due to connector locked state", self.vehicle.vin)
|
|
327
|
+
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_locked_date=element.last_changed)
|
|
275
328
|
try:
|
|
276
329
|
self.session.add(new_session)
|
|
277
330
|
self._update_session_odometer(new_session)
|
|
331
|
+
self._update_session_position(new_session)
|
|
278
332
|
LOG.debug('Added new charging session for vehicle %s to database', self.vehicle.vin)
|
|
279
333
|
self.last_charging_session = new_session
|
|
280
334
|
except DatabaseError as err:
|
|
@@ -283,8 +337,9 @@ class ChargingAgent(BaseAgent):
|
|
|
283
337
|
elif not self.last_charging_session.was_locked():
|
|
284
338
|
LOG.debug("Continuing existing charging session for vehicle %s, writing locked date", self.vehicle.vin)
|
|
285
339
|
try:
|
|
286
|
-
self.last_charging_session.plug_locked_date = element.
|
|
340
|
+
self.last_charging_session.plug_locked_date = element.last_changed
|
|
287
341
|
self._update_session_odometer(self.last_charging_session)
|
|
342
|
+
self._update_session_position(self.last_charging_session)
|
|
288
343
|
except DatabaseError as err:
|
|
289
344
|
self.session.rollback()
|
|
290
345
|
LOG.error('DatabaseError while starting charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
@@ -293,10 +348,32 @@ class ChargingAgent(BaseAgent):
|
|
|
293
348
|
if self.last_charging_session is not None and not self.last_charging_session.was_unlocked():
|
|
294
349
|
LOG.info("Writing plug unlocked date for charging session of vehicle %s", self.vehicle.vin)
|
|
295
350
|
try:
|
|
296
|
-
self.last_charging_session.plug_unlocked_date = element.
|
|
351
|
+
self.last_charging_session.plug_unlocked_date = element.last_changed
|
|
297
352
|
except DatabaseError as err:
|
|
298
353
|
self.session.rollback()
|
|
299
354
|
LOG.error('DatabaseError while ending charging session for vehicle %s in database: %s', self.vehicle.vin, err)
|
|
355
|
+
# Create charging session when locked at startup
|
|
356
|
+
elif element.value == ChargingConnector.ChargingConnectorLockState.LOCKED \
|
|
357
|
+
and self.carconnectivity_last_connector_lock_state == ChargingConnector.ChargingConnectorLockState.LOCKED:
|
|
358
|
+
if self.last_charging_session is None or self.last_charging_session.is_closed():
|
|
359
|
+
LOG.info("Starting new charging session for vehicle %s due to connector locked state", self.vehicle.vin)
|
|
360
|
+
new_session: ChargingSession = ChargingSession(vin=self.vehicle.vin, plug_locked_date=element.last_changed)
|
|
361
|
+
try:
|
|
362
|
+
self.session.add(new_session)
|
|
363
|
+
self._update_session_odometer(new_session)
|
|
364
|
+
self._update_session_position(new_session)
|
|
365
|
+
LOG.debug('Added new charging session for vehicle %s to database', self.vehicle.vin)
|
|
366
|
+
self.last_charging_session = new_session
|
|
367
|
+
except DatabaseError as err:
|
|
368
|
+
self.session.rollback()
|
|
369
|
+
LOG.error('DatabaseError while adding charging session for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
370
|
+
elif self.last_charging_session is not None and not self.last_charging_session.was_locked():
|
|
371
|
+
try:
|
|
372
|
+
self.last_charging_session.plug_locked_date = element.last_changed
|
|
373
|
+
LOG.info("Writing plug locked date for charging session of vehicle %s", self.vehicle.vin)
|
|
374
|
+
except DatabaseError as err:
|
|
375
|
+
self.session.rollback()
|
|
376
|
+
LOG.error('DatabaseError while changing charging session for vehicle %s to database: %s', self.vehicle.vin, err)
|
|
300
377
|
self.carconnectivity_last_connector_lock_state = element.value
|
|
301
378
|
|
|
302
379
|
def _update_session_odometer(self, charging_session: ChargingSession) -> None:
|
|
@@ -310,6 +387,18 @@ class ChargingAgent(BaseAgent):
|
|
|
310
387
|
self.session.rollback()
|
|
311
388
|
LOG.error('DatabaseError while updating odometer for charging session of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
312
389
|
|
|
390
|
+
def _update_session_charging_type(self, charging_session: ChargingSession) -> None:
|
|
391
|
+
if self.vehicle.carconnectivity_vehicle is None:
|
|
392
|
+
raise ValueError("Vehicle's carconnectivity_vehicle attribute is None")
|
|
393
|
+
if isinstance(self.vehicle.carconnectivity_vehicle, ElectricVehicle) and self.vehicle.carconnectivity_vehicle.charging.type.enabled \
|
|
394
|
+
and self.vehicle.carconnectivity_vehicle.charging.type.value is not None:
|
|
395
|
+
if charging_session.charging_type is None:
|
|
396
|
+
try:
|
|
397
|
+
charging_session.charging_type = self.vehicle.carconnectivity_vehicle.charging.type.value
|
|
398
|
+
except DatabaseError as err:
|
|
399
|
+
self.session.rollback()
|
|
400
|
+
LOG.error('DatabaseError while updating charging type for charging session of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
401
|
+
|
|
313
402
|
def _update_session_position(self, charging_session: ChargingSession) -> None:
|
|
314
403
|
if self.vehicle.carconnectivity_vehicle is None:
|
|
315
404
|
raise ValueError("Vehicle's carconnectivity_vehicle attribute is None")
|
|
@@ -324,3 +413,22 @@ class ChargingAgent(BaseAgent):
|
|
|
324
413
|
except DatabaseError as err:
|
|
325
414
|
self.session.rollback()
|
|
326
415
|
LOG.error('DatabaseError while updating position for charging session of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
416
|
+
if charging_session.location is None and self.vehicle.carconnectivity_vehicle.position.location.enabled:
|
|
417
|
+
location: Location = Location.from_carconnectivity_location(location=self.vehicle.carconnectivity_vehicle.position.location)
|
|
418
|
+
try:
|
|
419
|
+
location = self.session.merge(location)
|
|
420
|
+
charging_session.location = location
|
|
421
|
+
except DatabaseError as err:
|
|
422
|
+
self.session.rollback()
|
|
423
|
+
LOG.error('DatabaseError while merging location for charging session of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
424
|
+
if charging_session.charging_station is None \
|
|
425
|
+
and isinstance(self.vehicle.carconnectivity_vehicle, ElectricVehicle) and self.vehicle.carconnectivity_vehicle.charging is not None \
|
|
426
|
+
and self.vehicle.carconnectivity_vehicle.charging.enabled and self.vehicle.carconnectivity_vehicle.charging.charging_station.enabled:
|
|
427
|
+
charging_station: ChargingStation = ChargingStation.from_carconnectivity_charging_station(
|
|
428
|
+
charging_station=self.vehicle.carconnectivity_vehicle.charging.charging_station)
|
|
429
|
+
try:
|
|
430
|
+
charging_station = self.session.merge(charging_station)
|
|
431
|
+
charging_session.charging_station = charging_station
|
|
432
|
+
except DatabaseError as err:
|
|
433
|
+
self.session.rollback()
|
|
434
|
+
LOG.error('DatabaseError while merging charging station for charging session of vehicle %s in database: %s', self.vehicle.vin, err)
|
|
@@ -10,6 +10,7 @@ from carconnectivity.observable import Observable
|
|
|
10
10
|
from carconnectivity_plugins.database.agents.base_agent import BaseAgent
|
|
11
11
|
from carconnectivity_plugins.database.model.drive_level import DriveLevel
|
|
12
12
|
from carconnectivity_plugins.database.model.drive_range import DriveRange
|
|
13
|
+
from carconnectivity_plugins.database.model.drive_range_full import DriveRangeEstimatedFull
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
15
16
|
from typing import Optional
|
|
@@ -22,6 +23,7 @@ if TYPE_CHECKING:
|
|
|
22
23
|
|
|
23
24
|
LOG: logging.Logger = logging.getLogger("carconnectivity.plugins.database.agents.drive_state_agent")
|
|
24
25
|
|
|
26
|
+
|
|
25
27
|
class DriveStateAgent(BaseAgent):
|
|
26
28
|
def __init__(self, session: Session, drive: Drive) -> None:
|
|
27
29
|
if drive is None or drive.carconnectivity_drive is None:
|
|
@@ -31,6 +33,8 @@ class DriveStateAgent(BaseAgent):
|
|
|
31
33
|
|
|
32
34
|
self.last_level: Optional[DriveLevel] = session.query(DriveLevel).filter(DriveLevel.drive_id == drive.id).order_by(DriveLevel.first_date.desc()).first()
|
|
33
35
|
self.last_range: Optional[DriveRange] = session.query(DriveRange).filter(DriveRange.drive_id == drive.id).order_by(DriveRange.first_date.desc()).first()
|
|
36
|
+
self.last_range_estimated_full: Optional[DriveRangeEstimatedFull] = session.query(DriveRangeEstimatedFull) \
|
|
37
|
+
.filter(DriveRangeEstimatedFull.drive_id == drive.id).order_by(DriveRangeEstimatedFull.first_date.desc()).first()
|
|
34
38
|
|
|
35
39
|
drive.carconnectivity_drive.level.add_observer(self.__on_level_change, Observable.ObserverEvent.UPDATED)
|
|
36
40
|
if drive.carconnectivity_drive.level.enabled:
|
|
@@ -40,6 +44,10 @@ class DriveStateAgent(BaseAgent):
|
|
|
40
44
|
if drive.carconnectivity_drive.range.enabled:
|
|
41
45
|
self.__on_range_change(drive.carconnectivity_drive.range, Observable.ObserverEvent.UPDATED)
|
|
42
46
|
|
|
47
|
+
drive.carconnectivity_drive.range_estimated_full.add_observer(self.__on_range_estimated_full_change, Observable.ObserverEvent.UPDATED)
|
|
48
|
+
if drive.carconnectivity_drive.range_estimated_full.enabled:
|
|
49
|
+
self.__on_range_estimated_full_change(drive.carconnectivity_drive.range_estimated_full, Observable.ObserverEvent.UPDATED)
|
|
50
|
+
|
|
43
51
|
def __on_level_change(self, element: LevelAttribute, flags: Observable.ObserverEvent) -> None:
|
|
44
52
|
del flags
|
|
45
53
|
if element.enabled:
|
|
@@ -48,7 +56,7 @@ class DriveStateAgent(BaseAgent):
|
|
|
48
56
|
if (self.last_level is None or self.last_level.level != element.value) \
|
|
49
57
|
and element.last_updated is not None:
|
|
50
58
|
new_level: DriveLevel = DriveLevel(drive_id=self.drive.id, first_date=element.last_updated, last_date=element.last_updated,
|
|
51
|
-
|
|
59
|
+
level=element.value)
|
|
52
60
|
try:
|
|
53
61
|
self.session.add(new_level)
|
|
54
62
|
LOG.debug('Added new level %s for drive %s to database', element.value, self.drive.id)
|
|
@@ -74,7 +82,7 @@ class DriveStateAgent(BaseAgent):
|
|
|
74
82
|
if (self.last_range is None or self.last_range.range != element.value) \
|
|
75
83
|
and element.last_updated is not None:
|
|
76
84
|
new_range: DriveRange = DriveRange(drive_id=self.drive.id, first_date=element.last_updated, last_date=element.last_updated,
|
|
77
|
-
|
|
85
|
+
range=element.value)
|
|
78
86
|
try:
|
|
79
87
|
self.session.add(new_range)
|
|
80
88
|
LOG.debug('Added new range %s for drive %s to database', element.value, self.drive.id)
|
|
@@ -91,3 +99,29 @@ class DriveStateAgent(BaseAgent):
|
|
|
91
99
|
except DatabaseError as err:
|
|
92
100
|
self.session.rollback()
|
|
93
101
|
LOG.error('DatabaseError while updating range for drive %s in database: %s', self.drive.id, err)
|
|
102
|
+
|
|
103
|
+
def __on_range_estimated_full_change(self, element: RangeAttribute, flags: Observable.ObserverEvent) -> None:
|
|
104
|
+
del flags
|
|
105
|
+
if element.enabled:
|
|
106
|
+
if self.last_range_estimated_full is not None:
|
|
107
|
+
self.session.refresh(self.last_range_estimated_full)
|
|
108
|
+
if (self.last_range_estimated_full is None or self.last_range_estimated_full.range_estimated_full != element.value) \
|
|
109
|
+
and element.last_updated is not None:
|
|
110
|
+
new_range: DriveRangeEstimatedFull = DriveRangeEstimatedFull(drive_id=self.drive.id, first_date=element.last_updated,
|
|
111
|
+
last_date=element.last_updated, range_estimated_full=element.value)
|
|
112
|
+
try:
|
|
113
|
+
self.session.add(new_range)
|
|
114
|
+
LOG.debug('Added new range_estimated_full %s for drive %s to database', element.value, self.drive.id)
|
|
115
|
+
self.last_range_estimated_full = new_range
|
|
116
|
+
except DatabaseError as err:
|
|
117
|
+
self.session.rollback()
|
|
118
|
+
LOG.error('DatabaseError while adding range_estimated_full for drive %s to database: %s', self.drive.id, err)
|
|
119
|
+
elif self.last_range_estimated_full is not None and self.last_range_estimated_full.range_estimated_full == element.value \
|
|
120
|
+
and element.last_updated is not None:
|
|
121
|
+
if self.last_range_estimated_full.last_date is None or element.last_updated > self.last_range_estimated_full.last_date:
|
|
122
|
+
try:
|
|
123
|
+
self.last_range_estimated_full.last_date = element.last_updated
|
|
124
|
+
LOG.debug('Updated range_estimated_full %s for drive %s in database', element.value, self.drive.id)
|
|
125
|
+
except DatabaseError as err:
|
|
126
|
+
self.session.rollback()
|
|
127
|
+
LOG.error('DatabaseError while updating range_estimated_full for drive %s in database: %s', self.drive.id, err)
|
|
@@ -90,7 +90,7 @@ class TripAgent(BaseAgent):
|
|
|
90
90
|
if self.trip is not None:
|
|
91
91
|
LOG.info("Ending trip for vehicle %s", self.vehicle.vin)
|
|
92
92
|
try:
|
|
93
|
-
self.trip.
|
|
93
|
+
self.trip.destination_date = element.last_updated if element.last_updated is not None else datetime.now(tz=timezone.utc)
|
|
94
94
|
if self.vehicle.carconnectivity_vehicle.odometer.enabled and \
|
|
95
95
|
self.vehicle.carconnectivity_vehicle.odometer.value is not None:
|
|
96
96
|
self.trip.destination_odometer = self.vehicle.carconnectivity_vehicle.odometer.value
|
|
@@ -4,11 +4,14 @@ from .charging_state import ChargingState # noqa: F401
|
|
|
4
4
|
from .charging_rate import ChargingRate # noqa: F401
|
|
5
5
|
from .charging_power import ChargingPower # noqa: F401
|
|
6
6
|
from .charging_session import ChargingSession # noqa: F401
|
|
7
|
+
from .charging_station import ChargingStation # noqa: F401
|
|
7
8
|
from .climatization_state import ClimatizationState # noqa: F401
|
|
9
|
+
from .connection_state import ConnectionState # noqa: F401
|
|
8
10
|
from .drive import Drive # noqa: F401
|
|
9
11
|
from .drive_level import DriveLevel # noqa: F401
|
|
10
12
|
from .drive_range import DriveRange # noqa: F401
|
|
11
|
-
from .
|
|
13
|
+
from .drive_range_full import DriveRangeEstimatedFull # noqa: F401
|
|
14
|
+
from .location import Location # noqa: F401
|
|
12
15
|
from .outside_temperature import OutsideTemperature # noqa: F401
|
|
13
16
|
from .state import State # noqa: F401
|
|
14
17
|
from .tag import Tag # noqa: F401
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
""" This module contains the Vehicle charging power database model"""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
from sqlalchemy import ForeignKey
|
|
7
|
+
from sqlalchemy import ForeignKey, UniqueConstraint
|
|
8
8
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
9
9
|
|
|
10
10
|
from sqlalchemy_utc import UtcDateTime
|
|
@@ -12,6 +12,10 @@ from sqlalchemy_utc import UtcDateTime
|
|
|
12
12
|
from carconnectivity_plugins.database.model.base import Base
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from sqlalchemy import Constraint
|
|
17
|
+
|
|
18
|
+
|
|
15
19
|
class ChargingPower(Base): # pylint: disable=too-few-public-methods
|
|
16
20
|
"""
|
|
17
21
|
SQLAlchemy model representing a vehicle's charging power information over a time period.
|
|
@@ -32,6 +36,7 @@ class ChargingPower(Base): # pylint: disable=too-few-public-methods
|
|
|
32
36
|
"""
|
|
33
37
|
|
|
34
38
|
__tablename__: str = 'charging_powers'
|
|
39
|
+
__table_args__: tuple[Constraint] = (UniqueConstraint("vin", "first_date", name="vin_first_date"),)
|
|
35
40
|
|
|
36
41
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
37
42
|
vin: Mapped[str] = mapped_column(ForeignKey("vehicles.vin"))
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
""" This module contains the Vehicle charging rates database model"""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
from sqlalchemy import ForeignKey
|
|
7
|
+
from sqlalchemy import ForeignKey, UniqueConstraint
|
|
8
8
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
9
9
|
|
|
10
10
|
from sqlalchemy_utc import UtcDateTime
|
|
@@ -12,6 +12,10 @@ from sqlalchemy_utc import UtcDateTime
|
|
|
12
12
|
from carconnectivity_plugins.database.model.base import Base
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from sqlalchemy import Constraint
|
|
17
|
+
|
|
18
|
+
|
|
15
19
|
class ChargingRate(Base): # pylint: disable=too-few-public-methods
|
|
16
20
|
"""
|
|
17
21
|
SQLAlchemy model representing a vehicle's charging type information over a time period.
|
|
@@ -32,6 +36,7 @@ class ChargingRate(Base): # pylint: disable=too-few-public-methods
|
|
|
32
36
|
"""
|
|
33
37
|
|
|
34
38
|
__tablename__: str = 'charging_rates'
|
|
39
|
+
__table_args__: tuple[Constraint] = (UniqueConstraint("vin", "first_date", name="vin_first_date"),)
|
|
35
40
|
|
|
36
41
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
37
42
|
vin: Mapped[str] = mapped_column(ForeignKey("vehicles.vin"))
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
""" This module contains the Vehicle charging sessions database model"""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
from sqlalchemy import ForeignKey, Table, Column
|
|
7
|
+
from sqlalchemy import ForeignKey, Table, Column, UniqueConstraint
|
|
8
8
|
from sqlalchemy.orm import Mapped, mapped_column, relationship, backref
|
|
9
9
|
|
|
10
10
|
from sqlalchemy_utc import UtcDateTime
|
|
@@ -14,6 +14,10 @@ from carconnectivity.charging import Charging
|
|
|
14
14
|
from carconnectivity_plugins.database.model.base import Base
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from sqlalchemy import Constraint
|
|
19
|
+
|
|
20
|
+
|
|
17
21
|
charging_tag_association_table = Table('charging_sessions_tags', Base.metadata,
|
|
18
22
|
Column('charging_sessions_id', ForeignKey('charging_sessions.id')),
|
|
19
23
|
Column('tags_name', ForeignKey('tags.name'))
|
|
@@ -51,6 +55,7 @@ class ChargingSession(Base): # pylint: disable=too-few-public-methods
|
|
|
51
55
|
"""
|
|
52
56
|
|
|
53
57
|
__tablename__: str = 'charging_sessions'
|
|
58
|
+
__table_args__: tuple[Constraint] = (UniqueConstraint("vin", "session_start_date", name="vin_session_start_date"),)
|
|
54
59
|
|
|
55
60
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
56
61
|
vin: Mapped[str] = mapped_column(ForeignKey("vehicles.vin"))
|
|
@@ -68,6 +73,17 @@ class ChargingSession(Base): # pylint: disable=too-few-public-methods
|
|
|
68
73
|
session_position_longitude: Mapped[Optional[float]]
|
|
69
74
|
session_odometer: Mapped[Optional[float]]
|
|
70
75
|
charging_type: Mapped[Optional[Charging.ChargingType]]
|
|
76
|
+
location_uid: Mapped[Optional[str]] = mapped_column(ForeignKey("locations.uid"))
|
|
77
|
+
location: Mapped[Optional["Location"]] = relationship("Location")
|
|
78
|
+
charging_station_uid: Mapped[Optional[str]] = mapped_column(ForeignKey("charging_stations.uid"))
|
|
79
|
+
charging_station: Mapped[Optional["ChargingStation"]] = relationship("ChargingStation")
|
|
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]]
|
|
71
87
|
tags: Mapped[list["Tag"]] = relationship("Tag", secondary=charging_tag_association_table, backref=backref("charging_sessions"))
|
|
72
88
|
|
|
73
89
|
# pylint: disable-next=too-many-arguments, too-many-positional-arguments
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
""" This module contains the Vehicle charging state database model"""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
4
|
|
|
5
5
|
from datetime import datetime
|
|
6
6
|
|
|
7
|
-
from sqlalchemy import ForeignKey
|
|
7
|
+
from sqlalchemy import ForeignKey, UniqueConstraint
|
|
8
8
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
9
9
|
|
|
10
10
|
from sqlalchemy_utc import UtcDateTime
|
|
@@ -13,6 +13,9 @@ from carconnectivity.charging import Charging
|
|
|
13
13
|
|
|
14
14
|
from carconnectivity_plugins.database.model.base import Base
|
|
15
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from sqlalchemy import Constraint
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
class ChargingState(Base): # pylint: disable=too-few-public-methods
|
|
18
21
|
"""
|
|
@@ -38,6 +41,7 @@ class ChargingState(Base): # pylint: disable=too-few-public-methods
|
|
|
38
41
|
state (Optional[Charging.ChargingState]): The charging state value.
|
|
39
42
|
"""
|
|
40
43
|
__tablename__: str = 'charging_states'
|
|
44
|
+
__table_args__: tuple[Constraint] = (UniqueConstraint("vin", "first_date", name="vin_first_date"),)
|
|
41
45
|
|
|
42
46
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
43
47
|
vin: Mapped[str] = mapped_column(ForeignKey("vehicles.vin"))
|