arthexis 0.1.9__py3-none-any.whl → 0.1.26__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 arthexis might be problematic. Click here for more details.
- arthexis-0.1.26.dist-info/METADATA +272 -0
- arthexis-0.1.26.dist-info/RECORD +111 -0
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/licenses/LICENSE +674 -674
- config/__init__.py +5 -5
- config/active_app.py +15 -15
- config/asgi.py +29 -29
- config/auth_app.py +7 -7
- config/celery.py +32 -25
- config/context_processors.py +67 -68
- config/horologia_app.py +7 -7
- config/loadenv.py +11 -11
- config/logging.py +59 -48
- config/middleware.py +71 -25
- config/offline.py +49 -49
- config/settings.py +676 -492
- config/settings_helpers.py +109 -0
- config/urls.py +228 -159
- config/wsgi.py +17 -17
- core/admin.py +4052 -2066
- core/admin_history.py +50 -50
- core/admindocs.py +192 -151
- core/apps.py +350 -223
- core/auto_upgrade.py +72 -0
- core/backends.py +311 -124
- core/changelog.py +403 -0
- core/entity.py +149 -133
- core/environment.py +60 -43
- core/fields.py +168 -75
- core/form_fields.py +75 -0
- core/github_helper.py +188 -25
- core/github_issues.py +183 -172
- core/github_repos.py +72 -0
- core/lcd_screen.py +78 -78
- core/liveupdate.py +25 -25
- core/log_paths.py +114 -100
- core/mailer.py +89 -83
- core/middleware.py +91 -91
- core/models.py +5041 -2195
- core/notifications.py +105 -105
- core/public_wifi.py +267 -227
- core/reference_utils.py +107 -0
- core/release.py +940 -346
- core/rfid_import_export.py +113 -0
- core/sigil_builder.py +149 -131
- core/sigil_context.py +20 -20
- core/sigil_resolver.py +250 -284
- core/system.py +1425 -230
- core/tasks.py +538 -199
- core/temp_passwords.py +181 -0
- core/test_system_info.py +202 -43
- core/tests.py +2673 -1069
- core/tests_liveupdate.py +17 -17
- core/urls.py +11 -11
- core/user_data.py +681 -495
- core/views.py +2484 -789
- core/widgets.py +213 -51
- nodes/admin.py +2236 -445
- nodes/apps.py +98 -70
- nodes/backends.py +160 -53
- nodes/dns.py +203 -0
- nodes/feature_checks.py +133 -0
- nodes/lcd.py +165 -165
- nodes/models.py +2375 -870
- nodes/reports.py +411 -0
- nodes/rfid_sync.py +210 -0
- nodes/signals.py +18 -0
- nodes/tasks.py +141 -46
- nodes/tests.py +5045 -1489
- nodes/urls.py +29 -13
- nodes/utils.py +172 -73
- nodes/views.py +1768 -304
- ocpp/admin.py +1775 -481
- ocpp/apps.py +25 -25
- ocpp/consumers.py +1843 -630
- ocpp/evcs.py +844 -928
- ocpp/evcs_discovery.py +158 -0
- ocpp/models.py +1417 -640
- ocpp/network.py +398 -0
- ocpp/reference_utils.py +42 -0
- ocpp/routing.py +11 -9
- ocpp/simulator.py +745 -368
- ocpp/status_display.py +26 -0
- ocpp/store.py +603 -403
- ocpp/tasks.py +479 -31
- ocpp/test_export_import.py +131 -130
- ocpp/test_rfid.py +1072 -540
- ocpp/tests.py +5494 -2296
- ocpp/transactions_io.py +197 -165
- ocpp/urls.py +50 -50
- ocpp/views.py +2024 -912
- pages/admin.py +1123 -396
- pages/apps.py +45 -10
- pages/checks.py +40 -40
- pages/context_processors.py +151 -85
- pages/defaults.py +13 -0
- pages/forms.py +221 -0
- pages/middleware.py +213 -153
- pages/models.py +720 -252
- pages/module_defaults.py +156 -0
- pages/site_config.py +137 -0
- pages/tasks.py +74 -0
- pages/tests.py +4009 -1389
- pages/urls.py +38 -20
- pages/utils.py +93 -12
- pages/views.py +1736 -762
- arthexis-0.1.9.dist-info/METADATA +0 -168
- arthexis-0.1.9.dist-info/RECORD +0 -92
- core/workgroup_urls.py +0 -17
- core/workgroup_views.py +0 -94
- nodes/actions.py +0 -70
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/WHEEL +0 -0
- {arthexis-0.1.9.dist-info → arthexis-0.1.26.dist-info}/top_level.txt +0 -0
ocpp/transactions_io.py
CHANGED
|
@@ -1,165 +1,197 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from typing import Iterable
|
|
5
|
-
|
|
6
|
-
from django.
|
|
7
|
-
from django.utils
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
.
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
),
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
),
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Iterable
|
|
5
|
+
|
|
6
|
+
from django.core.exceptions import ValidationError
|
|
7
|
+
from django.utils import timezone
|
|
8
|
+
from django.utils.dateparse import parse_datetime
|
|
9
|
+
|
|
10
|
+
from .models import Charger, Transaction, MeterValue
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def export_transactions(
|
|
14
|
+
start: datetime | None = None,
|
|
15
|
+
end: datetime | None = None,
|
|
16
|
+
chargers: Iterable[str] | None = None,
|
|
17
|
+
) -> dict:
|
|
18
|
+
"""Return transaction export data."""
|
|
19
|
+
qs = (
|
|
20
|
+
Transaction.objects.all()
|
|
21
|
+
.select_related("charger")
|
|
22
|
+
.prefetch_related("meter_values")
|
|
23
|
+
)
|
|
24
|
+
if start:
|
|
25
|
+
qs = qs.filter(start_time__gte=start)
|
|
26
|
+
if end:
|
|
27
|
+
qs = qs.filter(start_time__lte=end)
|
|
28
|
+
if chargers:
|
|
29
|
+
qs = qs.filter(charger__charger_id__in=chargers)
|
|
30
|
+
|
|
31
|
+
export_chargers = set(qs.values_list("charger__charger_id", flat=True))
|
|
32
|
+
data = {"chargers": [], "transactions": []}
|
|
33
|
+
|
|
34
|
+
for charger in Charger.objects.filter(charger_id__in=export_chargers):
|
|
35
|
+
data["chargers"].append(
|
|
36
|
+
{
|
|
37
|
+
"charger_id": charger.charger_id,
|
|
38
|
+
"connector_id": charger.connector_id,
|
|
39
|
+
"require_rfid": charger.require_rfid,
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
for tx in qs:
|
|
44
|
+
data["transactions"].append(
|
|
45
|
+
{
|
|
46
|
+
"charger": tx.charger.charger_id if tx.charger else None,
|
|
47
|
+
"account": tx.account_id,
|
|
48
|
+
"rfid": tx.rfid,
|
|
49
|
+
"vid": tx.vehicle_identifier,
|
|
50
|
+
"vin": tx.vin,
|
|
51
|
+
"meter_start": tx.meter_start,
|
|
52
|
+
"meter_stop": tx.meter_stop,
|
|
53
|
+
"voltage_start": tx.voltage_start,
|
|
54
|
+
"voltage_stop": tx.voltage_stop,
|
|
55
|
+
"current_import_start": tx.current_import_start,
|
|
56
|
+
"current_import_stop": tx.current_import_stop,
|
|
57
|
+
"current_offered_start": tx.current_offered_start,
|
|
58
|
+
"current_offered_stop": tx.current_offered_stop,
|
|
59
|
+
"temperature_start": tx.temperature_start,
|
|
60
|
+
"temperature_stop": tx.temperature_stop,
|
|
61
|
+
"soc_start": tx.soc_start,
|
|
62
|
+
"soc_stop": tx.soc_stop,
|
|
63
|
+
"start_time": tx.start_time.isoformat(),
|
|
64
|
+
"stop_time": tx.stop_time.isoformat() if tx.stop_time else None,
|
|
65
|
+
"received_start_time": tx.received_start_time.isoformat()
|
|
66
|
+
if tx.received_start_time
|
|
67
|
+
else None,
|
|
68
|
+
"received_stop_time": tx.received_stop_time.isoformat()
|
|
69
|
+
if tx.received_stop_time
|
|
70
|
+
else None,
|
|
71
|
+
"meter_values": [
|
|
72
|
+
{
|
|
73
|
+
"connector_id": mv.connector_id,
|
|
74
|
+
"timestamp": mv.timestamp.isoformat(),
|
|
75
|
+
"context": mv.context,
|
|
76
|
+
"energy": str(mv.energy) if mv.energy is not None else None,
|
|
77
|
+
"voltage": str(mv.voltage) if mv.voltage is not None else None,
|
|
78
|
+
"current_import": (
|
|
79
|
+
str(mv.current_import)
|
|
80
|
+
if mv.current_import is not None
|
|
81
|
+
else None
|
|
82
|
+
),
|
|
83
|
+
"current_offered": (
|
|
84
|
+
str(mv.current_offered)
|
|
85
|
+
if mv.current_offered is not None
|
|
86
|
+
else None
|
|
87
|
+
),
|
|
88
|
+
"temperature": (
|
|
89
|
+
str(mv.temperature) if mv.temperature is not None else None
|
|
90
|
+
),
|
|
91
|
+
"soc": str(mv.soc) if mv.soc is not None else None,
|
|
92
|
+
}
|
|
93
|
+
for mv in tx.meter_values.all()
|
|
94
|
+
],
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
return data
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _parse_dt(value: str | None) -> datetime | None:
|
|
101
|
+
if value is None:
|
|
102
|
+
return None
|
|
103
|
+
dt = parse_datetime(value)
|
|
104
|
+
if dt is None:
|
|
105
|
+
raise ValueError(f"Invalid datetime: {value}")
|
|
106
|
+
if timezone.is_naive(dt):
|
|
107
|
+
dt = timezone.make_aware(dt)
|
|
108
|
+
return dt
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def import_transactions(data: dict) -> int:
|
|
112
|
+
"""Import transactions from export data.
|
|
113
|
+
|
|
114
|
+
Returns number of imported transactions.
|
|
115
|
+
"""
|
|
116
|
+
charger_map: dict[str, Charger] = {}
|
|
117
|
+
for item in data.get("chargers", []):
|
|
118
|
+
try:
|
|
119
|
+
serial = Charger.validate_serial(item.get("charger_id"))
|
|
120
|
+
except ValidationError:
|
|
121
|
+
continue
|
|
122
|
+
connector_value = item.get("connector_id", None)
|
|
123
|
+
if connector_value in ("", None):
|
|
124
|
+
connector_value = None
|
|
125
|
+
elif isinstance(connector_value, str):
|
|
126
|
+
connector_value = int(connector_value)
|
|
127
|
+
charger, _ = Charger.objects.get_or_create(
|
|
128
|
+
charger_id=serial,
|
|
129
|
+
defaults={
|
|
130
|
+
"connector_id": connector_value,
|
|
131
|
+
"require_rfid": item.get("require_rfid", False),
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
charger_map[serial] = charger
|
|
135
|
+
|
|
136
|
+
imported = 0
|
|
137
|
+
for tx in data.get("transactions", []):
|
|
138
|
+
serial = Charger.normalize_serial(tx.get("charger"))
|
|
139
|
+
if not serial or Charger.is_placeholder_serial(serial):
|
|
140
|
+
continue
|
|
141
|
+
charger = charger_map.get(serial)
|
|
142
|
+
if charger is None:
|
|
143
|
+
try:
|
|
144
|
+
charger, _ = Charger.objects.get_or_create(charger_id=serial)
|
|
145
|
+
except ValidationError:
|
|
146
|
+
continue
|
|
147
|
+
charger_map[serial] = charger
|
|
148
|
+
vid_value = tx.get("vid")
|
|
149
|
+
vin_value = tx.get("vin")
|
|
150
|
+
vid_text = str(vid_value).strip() if vid_value is not None else ""
|
|
151
|
+
vin_text = str(vin_value).strip() if vin_value is not None else ""
|
|
152
|
+
if not vid_text and vin_text:
|
|
153
|
+
vid_text = vin_text
|
|
154
|
+
transaction = Transaction.objects.create(
|
|
155
|
+
charger=charger,
|
|
156
|
+
account_id=tx.get("account"),
|
|
157
|
+
rfid=tx.get("rfid", ""),
|
|
158
|
+
vid=vid_text,
|
|
159
|
+
vin=vin_text,
|
|
160
|
+
meter_start=tx.get("meter_start"),
|
|
161
|
+
meter_stop=tx.get("meter_stop"),
|
|
162
|
+
voltage_start=tx.get("voltage_start"),
|
|
163
|
+
voltage_stop=tx.get("voltage_stop"),
|
|
164
|
+
current_import_start=tx.get("current_import_start"),
|
|
165
|
+
current_import_stop=tx.get("current_import_stop"),
|
|
166
|
+
current_offered_start=tx.get("current_offered_start"),
|
|
167
|
+
current_offered_stop=tx.get("current_offered_stop"),
|
|
168
|
+
temperature_start=tx.get("temperature_start"),
|
|
169
|
+
temperature_stop=tx.get("temperature_stop"),
|
|
170
|
+
soc_start=tx.get("soc_start"),
|
|
171
|
+
soc_stop=tx.get("soc_stop"),
|
|
172
|
+
start_time=_parse_dt(tx.get("start_time")),
|
|
173
|
+
stop_time=_parse_dt(tx.get("stop_time")),
|
|
174
|
+
received_start_time=_parse_dt(tx.get("received_start_time"))
|
|
175
|
+
or _parse_dt(tx.get("start_time")),
|
|
176
|
+
received_stop_time=_parse_dt(tx.get("received_stop_time"))
|
|
177
|
+
or _parse_dt(tx.get("stop_time")),
|
|
178
|
+
)
|
|
179
|
+
for mv in tx.get("meter_values", []):
|
|
180
|
+
connector_id = mv.get("connector_id")
|
|
181
|
+
if isinstance(connector_id, str):
|
|
182
|
+
connector_id = int(connector_id)
|
|
183
|
+
MeterValue.objects.create(
|
|
184
|
+
charger=charger,
|
|
185
|
+
transaction=transaction,
|
|
186
|
+
connector_id=connector_id,
|
|
187
|
+
timestamp=_parse_dt(mv.get("timestamp")),
|
|
188
|
+
context=mv.get("context", ""),
|
|
189
|
+
energy=mv.get("energy"),
|
|
190
|
+
voltage=mv.get("voltage"),
|
|
191
|
+
current_import=mv.get("current_import"),
|
|
192
|
+
current_offered=mv.get("current_offered"),
|
|
193
|
+
temperature=mv.get("temperature"),
|
|
194
|
+
soc=mv.get("soc"),
|
|
195
|
+
)
|
|
196
|
+
imported += 1
|
|
197
|
+
return imported
|
ocpp/urls.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
from django.urls import include, path
|
|
2
|
-
|
|
3
|
-
from . import views
|
|
4
|
-
|
|
5
|
-
urlpatterns = [
|
|
6
|
-
path("", views.dashboard, name="ocpp-dashboard"),
|
|
7
|
-
path("simulator/", views.cp_simulator, name="cp-simulator"),
|
|
8
|
-
path("chargers/", views.charger_list, name="charger-list"),
|
|
9
|
-
path("chargers/<str:cid>/", views.charger_detail, name="charger-detail"),
|
|
10
|
-
path(
|
|
11
|
-
"chargers/<str:cid>/connector/<slug:connector>/",
|
|
12
|
-
views.charger_detail,
|
|
13
|
-
name="charger-detail-connector",
|
|
14
|
-
),
|
|
15
|
-
path("chargers/<str:cid>/action/", views.dispatch_action, name="charger-action"),
|
|
16
|
-
path(
|
|
17
|
-
"chargers/<str:cid>/connector/<slug:connector>/action/",
|
|
18
|
-
views.dispatch_action,
|
|
19
|
-
name="charger-action-connector",
|
|
20
|
-
),
|
|
21
|
-
path("c/<str:cid>/", views.charger_page, name="charger-page"),
|
|
22
|
-
path(
|
|
23
|
-
"c/<str:cid>/connector/<slug:connector>/",
|
|
24
|
-
views.charger_page,
|
|
25
|
-
name="charger-page-connector",
|
|
26
|
-
),
|
|
27
|
-
path(
|
|
28
|
-
"c/<str:cid>/sessions/",
|
|
29
|
-
views.charger_session_search,
|
|
30
|
-
name="charger-session-search",
|
|
31
|
-
),
|
|
32
|
-
path(
|
|
33
|
-
"c/<str:cid>/connector/<slug:connector>/sessions/",
|
|
34
|
-
views.charger_session_search,
|
|
35
|
-
name="charger-session-search-connector",
|
|
36
|
-
),
|
|
37
|
-
path("log/<str:cid>/", views.charger_log_page, name="charger-log"),
|
|
38
|
-
path(
|
|
39
|
-
"log/<str:cid>/connector/<slug:connector>/",
|
|
40
|
-
views.charger_log_page,
|
|
41
|
-
name="charger-log-connector",
|
|
42
|
-
),
|
|
43
|
-
path("c/<str:cid>/status/", views.charger_status, name="charger-status"),
|
|
44
|
-
path(
|
|
45
|
-
"c/<str:cid>/connector/<slug:connector>/status/",
|
|
46
|
-
views.charger_status,
|
|
47
|
-
name="charger-status-connector",
|
|
48
|
-
),
|
|
49
|
-
path("rfid/", include("ocpp.rfid.urls")),
|
|
50
|
-
]
|
|
1
|
+
from django.urls import include, path
|
|
2
|
+
|
|
3
|
+
from . import views
|
|
4
|
+
|
|
5
|
+
urlpatterns = [
|
|
6
|
+
path("cpms/dashboard/", views.dashboard, name="ocpp-dashboard"),
|
|
7
|
+
path("evcs/simulator/", views.cp_simulator, name="cp-simulator"),
|
|
8
|
+
path("chargers/", views.charger_list, name="charger-list"),
|
|
9
|
+
path("chargers/<str:cid>/", views.charger_detail, name="charger-detail"),
|
|
10
|
+
path(
|
|
11
|
+
"chargers/<str:cid>/connector/<slug:connector>/",
|
|
12
|
+
views.charger_detail,
|
|
13
|
+
name="charger-detail-connector",
|
|
14
|
+
),
|
|
15
|
+
path("chargers/<str:cid>/action/", views.dispatch_action, name="charger-action"),
|
|
16
|
+
path(
|
|
17
|
+
"chargers/<str:cid>/connector/<slug:connector>/action/",
|
|
18
|
+
views.dispatch_action,
|
|
19
|
+
name="charger-action-connector",
|
|
20
|
+
),
|
|
21
|
+
path("c/<str:cid>/", views.charger_page, name="charger-page"),
|
|
22
|
+
path(
|
|
23
|
+
"c/<str:cid>/connector/<slug:connector>/",
|
|
24
|
+
views.charger_page,
|
|
25
|
+
name="charger-page-connector",
|
|
26
|
+
),
|
|
27
|
+
path(
|
|
28
|
+
"c/<str:cid>/sessions/",
|
|
29
|
+
views.charger_session_search,
|
|
30
|
+
name="charger-session-search",
|
|
31
|
+
),
|
|
32
|
+
path(
|
|
33
|
+
"c/<str:cid>/connector/<slug:connector>/sessions/",
|
|
34
|
+
views.charger_session_search,
|
|
35
|
+
name="charger-session-search-connector",
|
|
36
|
+
),
|
|
37
|
+
path("log/<str:cid>/", views.charger_log_page, name="charger-log"),
|
|
38
|
+
path(
|
|
39
|
+
"log/<str:cid>/connector/<slug:connector>/",
|
|
40
|
+
views.charger_log_page,
|
|
41
|
+
name="charger-log-connector",
|
|
42
|
+
),
|
|
43
|
+
path("c/<str:cid>/status/", views.charger_status, name="charger-status"),
|
|
44
|
+
path(
|
|
45
|
+
"c/<str:cid>/connector/<slug:connector>/status/",
|
|
46
|
+
views.charger_status,
|
|
47
|
+
name="charger-status-connector",
|
|
48
|
+
),
|
|
49
|
+
path("rfid/validator/", include("ocpp.rfid.urls")),
|
|
50
|
+
]
|