22
22
###########################################################################
23
23
24
24
from modules .OsmoseTranslation import T_
25
- from .Analyser_Merge import (
26
- Analyser_Merge_Point ,
27
- Source ,
28
- CSV ,
29
- Load_XY ,
30
- Conflate ,
31
- Select ,
32
- Mapping ,
33
- )
25
+ from .Analyser_Merge import Analyser_Merge_Point , Source , CSV , Load_XY , Conflate , Select , Mapping
34
26
35
27
36
28
class Analyser_Merge_Charging_station_FR (Analyser_Merge_Point ):
37
- # Constante pour limiter les valeurs aberrantes (en kW)
29
+ # constant to limit bad formatting in open data (in kW)
38
30
MAX_POWER_KW = 401
39
31
WIKIDATA_MAP = {
40
32
"ionity" : "Q42717773" ,
@@ -50,29 +42,27 @@ class Analyser_Merge_Charging_station_FR(Analyser_Merge_Point):
50
42
@staticmethod
51
43
def keepMaxValueIfEnum (str_val ):
52
44
53
- # si la valeur contient un ; on sépare et on prend la plus haute valeur
45
+ # if the value contains a semicolon, we split it and keep only the highest value
54
46
if ";" in str_val :
55
47
boom = str_val .split (";" )
56
48
max_val = 0
57
49
for p in boom :
58
- # Supprimer les unités éventuelles (comme "kw")
59
50
p_clean = p .lower ().replace ("kw" , "" ).strip ()
60
51
try :
61
52
p_val = int (float (p_clean ))
62
- # Ignorer les valeurs supérieures à la limite maximale connue (MAX_POWER_KW)
63
53
if (
64
54
p_val <= Analyser_Merge_Charging_station_FR .MAX_POWER_KW
65
55
and p_val > max_val
66
56
):
67
57
max_val = p_val
68
58
except ValueError :
69
- # Ignorer les valeurs qui ne peuvent pas être converties en nombre
59
+ # exclude values we can not convert to number
70
60
pass
71
61
72
62
if max_val > 0 :
73
63
str_val = str (max_val )
74
64
else :
75
- # Gérer les cas où il n'y a pas de délimiteur mais une unité est présente
65
+ # case without delimiter, handle unit
76
66
if "kw" in str_val .lower ():
77
67
p_clean = str_val .lower ().replace ("kw" , "" ).strip ()
78
68
try :
@@ -84,7 +74,7 @@ def keepMaxValueIfEnum(str_val):
84
74
return str_val
85
75
86
76
def _normalize_number (self , v : float ) -> str :
87
- """Formate un float en supprimant les .0 inutiles et les zéros de fin ."""
77
+ """Formats in float by removing unwanted zeros ."""
88
78
try :
89
79
iv = int (v )
90
80
if abs (v - iv ) < 1e-9 :
@@ -94,20 +84,7 @@ def _normalize_number(self, v: float) -> str:
94
84
return str (v )
95
85
96
86
def getPuissanceNominaleInKw (self , raw ):
97
- """
98
- Calcule la puissance nominale en kW à partir d'une valeur brute.
99
-
100
- Règles:
101
- - Si 'raw' est une énumération 'a;b;c', on garde la valeur max en kW <= MAX_POWER_KW.
102
- - Si 'raw' est une valeur unique:
103
- * suffixe 'kW' => valeur déjà en kW
104
- * suffixe 'W' => conversion W -> kW
105
- * sans unité:
106
- - si > MAX_POWER_KW => on suppose des watts, on divise par 1000
107
- - sinon => déjà en kW
108
-
109
- Retour: 'X kW' ou None si indéterminable.
110
- """
87
+ """Computes nominal power in kW from a possible enumeration of values."""
111
88
if raw is None :
112
89
return None
113
90
@@ -117,7 +94,7 @@ def getPuissanceNominaleInKw(self, raw):
117
94
118
95
max_kw = getattr (self , "MAX_POWER_KW" , 500 )
119
96
120
- # Cas énumération: on délègue à keepMaxValueIfEnum puis on formate .
97
+ # enumeration case: we only want the max value and format it .
121
98
if ";" in s :
122
99
max_str = self .keepMaxValueIfEnum (s )
123
100
if not max_str :
@@ -130,7 +107,7 @@ def getPuissanceNominaleInKw(self, raw):
130
107
return None
131
108
return f"{ self ._normalize_number (v )} kW"
132
109
133
- # Cas valeur unique
110
+ # case of only one value
134
111
s_norm = s .lower ().replace ("," , "." )
135
112
try :
136
113
if s_norm .endswith ("kw" ):
@@ -142,7 +119,7 @@ def getPuissanceNominaleInKw(self, raw):
142
119
v = v_w / 1000.0
143
120
return f"{ self ._normalize_number (v )} kW"
144
121
145
- # Sans unité
122
+ # case without unit
146
123
v = float (s_norm )
147
124
if v > max_kw :
148
125
# On suppose des watts => conversion en kW
@@ -154,73 +131,48 @@ def getPuissanceNominaleInKw(self, raw):
154
131
def __init__ (self , config , logger = None ):
155
132
Analyser_Merge_Point .__init__ (self , config , logger )
156
133
doc = dict (
157
- detail = T_ (
158
- """A car charging station may be here but is not mapped. The list of the
159
- charging stations comes from a database published by Etalab. This database
160
- brings together information published by the various local authorities and
161
- networks in France."""
162
- ),
163
- fix = T_ (
164
- """See [the
165
- mapping](https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques)
166
- on the wiki. Add a node or add tags if already existing."""
167
- ),
168
- trap = T_ (
169
- """The initial information corresponds to recharging pools and devices and not to
170
- stations, so some values are worth checking in the field. For instance, an open data point
171
- with `capacity=6` can sometimes match to 3 charging station with `capacity=2`"""
172
- ),
173
- )
174
- self .def_class_missing_official (
175
- item = 8410 ,
176
- id = 1 ,
177
- level = 3 ,
178
- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
179
- title = T_ ("Car charging station not integrated" ),
180
- ** doc ,
181
- )
182
- self .def_class_possible_merge (
183
- item = 8411 ,
184
- id = 3 ,
185
- level = 3 ,
186
- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
187
- title = T_ ("Car charging station, integration suggestion" ),
188
- ** doc ,
189
- )
190
- self .def_class_update_official (
191
- item = 8412 ,
192
- id = 4 ,
193
- level = 3 ,
194
- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
195
- title = T_ ("Car charging station update" ),
196
- ** doc ,
197
- )
134
+ detail = T_ (
135
+ '''A car charging station may be here but is not mapped. The list of the
136
+ charging stations comes from a database published by Etalab. This database
137
+ brings together information published by the various local authorities and
138
+ networks in France.''' ),
139
+ fix = T_ (
140
+ '''See [the
141
+ mapping](https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques)
142
+ on the wiki. Add a node or add tags if already existing.''' ),
143
+ trap = T_ (
144
+ '''The initial information corresponds to recharging pools and devices and not to
145
+ stations, so some values are worth checking in the field. For instance, an open data point
146
+ with `capacity=6` can sometimes match to 3 charging station with `capacity=2`''' ))
147
+ self .def_class_missing_official (item = 8410 , id = 1 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
148
+ title = T_ ('Car charging station not integrated' ), ** doc )
149
+ self .def_class_possible_merge (item = 8411 , id = 3 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
150
+ title = T_ ('Car charging station, integration suggestion' ), ** doc )
151
+ self .def_class_update_official (item = 8412 , id = 4 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
152
+ title = T_ ('Car charging station update' ), ** doc )
198
153
199
154
self .init (
200
155
"https://transport.data.gouv.fr/datasets/fichier-consolide-des-bornes-de-recharge-pour-vehicules-electriques/" ,
201
156
"Stations de recharge pour véhicules électriques" ,
202
- CSV (
203
- Source (
204
- attribution = "data.gouv.fr:Etalab" ,
205
- millesime = "05/2022" ,
206
- fileUrl = "https://raw.githubusercontent.com/Jungle-Bus/ref-EU-EVSE/gh-pages/opendata_stations.csv" ,
207
- )
208
- ),
157
+ CSV (Source (attribution = "data.gouv.fr:Etalab" , millesime = "05/2022" ,
158
+ fileUrl = "https://raw.githubusercontent.com/Jungle-Bus/ref-EU-EVSE/gh-pages/opendata_stations.csv" )),
209
159
Load_XY ("Xlongitude" , "Ylatitude" ),
210
160
Conflate (
211
161
select = Select (
212
- types = ["nodes" , "ways" ], tags = { "amenity" : "charging_station" }
213
- ),
162
+ types = ["nodes" , "ways" ],
163
+ tags = { "amenity" : "charging_station" } ),
214
164
conflationDistance = 100 ,
215
165
osmRef = "ref:EU:EVSE" ,
216
166
mapping = Mapping (
217
- static1 = {"amenity" : "charging_station" , "motorcar" : "yes" },
167
+ static1 = {
168
+ "amenity" : "charging_station" ,
169
+ "motorcar" : "yes" },
218
170
static2 = {"source" : self .source },
219
171
mapping1 = {
220
172
"operator" : "nom_operateur" ,
221
173
"network" : "nom_enseigne" ,
222
174
"owner" : "nom_amenageur" ,
223
- "ref:EU:EVSE" : "id_station_itinerance" ,
175
+ "ref:EU:EVSE" : "id_station_itinerance"
224
176
},
225
177
mapping2 = {
226
178
"charging_station:output" : lambda fields : self .getPuissanceNominaleInKw (
@@ -230,87 +182,20 @@ def __init__(self, config, logger=None):
230
182
"operator:email" : "contact_operateur" ,
231
183
"start_date" : "date_mise_en_service" ,
232
184
"capacity" : "nbre_pdc" ,
233
- "bicycle" : lambda fields : (
234
- "yes" if fields ["station_deux_roues" ] == "true" else None
235
- ),
236
- "motorcycle" : lambda fields : (
237
- "yes" if fields ["station_deux_roues" ] == "true" else None
238
- ),
239
- "moped" : lambda fields : (
240
- "yes" if fields ["station_deux_roues" ] == "true" else None
241
- ),
242
- "motorcar" : lambda fields : (
243
- "no" if fields ["station_deux_roues" ] == "true" else "yes"
244
- ),
185
+ "bicycle" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
186
+ "motorcycle" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
187
+ "moped" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
188
+ "motorcar" : lambda fields : "no" if fields ["station_deux_roues" ] == "true" else "yes" ,
245
189
"opening_hours" : "horaires_grouped" ,
246
- "fee" : lambda fields : (
247
- "yes"
248
- if fields ["gratuit_grouped" ] == "false"
249
- else ("no" if fields ["gratuit_grouped" ] == "true" else None )
250
- ),
251
- "authentication:none" : lambda fields : (
252
- "yes" if fields ["paiement_acte_grouped" ] == "true" else None
253
- ),
254
- "payment:credit_cards" : lambda fields : (
255
- "yes"
256
- if fields ["paiement_cb_grouped" ] == "true"
257
- else (
258
- "no"
259
- if fields ["paiement_cb_grouped" ] == "false"
260
- else None
261
- )
262
- ),
263
- "reservation" : lambda fields : (
264
- "yes" if fields ["reservation_grouped" ] == "true" else None
265
- ),
266
- "wheelchair" : lambda fields : (
267
- "yes"
268
- if fields ["accessibilite_pmr_grouped" ]
269
- == "Accessible mais non réservé PMR"
270
- else (
271
- "no"
272
- if fields ["accessibilite_pmr_grouped" ]
273
- == "Non accessible"
274
- else None
275
- )
276
- ),
277
- "socket:typee" : lambda fields : (
278
- fields ["nb_EF_grouped" ]
279
- if fields ["nb_EF_grouped" ] != "0"
280
- else None
281
- ),
282
- "socket:type2" : lambda fields : (
283
- fields ["nb_T2_grouped" ]
284
- if fields ["nb_T2_grouped" ] != "0"
285
- else None
286
- ),
287
- "socket:type2_combo" : lambda fields : (
288
- fields ["nb_combo_ccs_grouped" ]
289
- if fields ["nb_combo_ccs_grouped" ] != "0"
290
- else None
291
- ),
292
- "socket:chademo" : lambda fields : (
293
- fields ["nb_chademo_grouped" ]
294
- if fields ["nb_chademo_grouped" ] != "0"
295
- else None
296
- ),
297
- "wikimedia:network" : lambda fields : (
298
- self .WIKIDATA_MAP .get (fields ["nom_enseigne" ].lower (), None )
299
- if fields ["nom_enseigne" ] != "0"
300
- else None
301
- ),
302
- },
303
- text = lambda tags , fields : {
304
- "en" : "{0}, {1}, {2}" .format (
305
- fields ["nom_station" ],
306
- fields ["adresse_station" ],
307
- (
308
- fields ["observations" ]
309
- if fields ["observations" ] != "null"
310
- else "-"
311
- ),
312
- )
190
+ "fee" : lambda fields : "yes" if fields ["gratuit_grouped" ] == "false" else ("no" if fields ["gratuit_grouped" ] == "true" else None ),
191
+ "authentication:none" : lambda fields : "yes" if fields ["paiement_acte_grouped" ] == "true" else None ,
192
+ "payment:credit_cards" : lambda fields : "yes" if fields ["paiement_cb_grouped" ] == "true" else ("no" if fields ["paiement_cb_grouped" ] == "false" else None ),
193
+ "reservation" : lambda fields : "yes" if fields ["reservation_grouped" ] == "true" else None ,
194
+ "wheelchair" : lambda fields : "yes" if fields ["accessibilite_pmr_grouped" ] == "Accessible mais non réservé PMR" else ("no" if fields ["accessibilite_pmr_grouped" ] == "Non accessible" else None ),
195
+ "socket:typee" : lambda fields : fields ["nb_EF_grouped" ] if fields ["nb_EF_grouped" ] != "0" else None ,
196
+ "socket:type2" : lambda fields : fields ["nb_T2_grouped" ] if fields ["nb_T2_grouped" ] != "0" else None ,
197
+ "socket:type2_combo" : lambda fields : fields ["nb_combo_ccs_grouped" ] if fields ["nb_combo_ccs_grouped" ] != "0" else None ,
198
+ "socket:chademo" : lambda fields : fields ["nb_chademo_grouped" ] if fields ["nb_chademo_grouped" ] != "0" else None ,
199
+ "wikimedia:network" : lambda fields : self .WIKIDATA_MAP .get (fields ["nom_enseigne" ].lower (), None ) if fields ["nom_enseigne" ] != "0" else None ,
313
200
},
314
- ),
315
- ),
316
- )
201
+ text = lambda tags , fields : {"en" : "{0}, {1}, {2}" .format (fields ["nom_station" ], fields ["adresse_station" ], fields ["observations" ] if fields ["observations" ] != "null" else "-" )})))
0 commit comments