Skip to content

Commit 6ee895c

Browse files
committed
limit modifications for charging station max output, comments in english
1 parent 823df20 commit 6ee895c

File tree

2 files changed

+52
-257
lines changed

2 files changed

+52
-257
lines changed

analysers/analyser_merge_charging_station_FR.py

Lines changed: 52 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,11 @@
2222
###########################################################################
2323

2424
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
3426

3527

3628
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)
3830
MAX_POWER_KW = 401
3931
WIKIDATA_MAP = {
4032
"ionity": "Q42717773",
@@ -50,29 +42,27 @@ class Analyser_Merge_Charging_station_FR(Analyser_Merge_Point):
5042
@staticmethod
5143
def keepMaxValueIfEnum(str_val):
5244

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
5446
if ";" in str_val:
5547
boom = str_val.split(";")
5648
max_val = 0
5749
for p in boom:
58-
# Supprimer les unités éventuelles (comme "kw")
5950
p_clean = p.lower().replace("kw", "").strip()
6051
try:
6152
p_val = int(float(p_clean))
62-
# Ignorer les valeurs supérieures à la limite maximale connue (MAX_POWER_KW)
6353
if (
6454
p_val <= Analyser_Merge_Charging_station_FR.MAX_POWER_KW
6555
and p_val > max_val
6656
):
6757
max_val = p_val
6858
except ValueError:
69-
# Ignorer les valeurs qui ne peuvent pas être converties en nombre
59+
# exclude values we can not convert to number
7060
pass
7161

7262
if max_val > 0:
7363
str_val = str(max_val)
7464
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
7666
if "kw" in str_val.lower():
7767
p_clean = str_val.lower().replace("kw", "").strip()
7868
try:
@@ -84,7 +74,7 @@ def keepMaxValueIfEnum(str_val):
8474
return str_val
8575

8676
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."""
8878
try:
8979
iv = int(v)
9080
if abs(v - iv) < 1e-9:
@@ -94,20 +84,7 @@ def _normalize_number(self, v: float) -> str:
9484
return str(v)
9585

9686
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."""
11188
if raw is None:
11289
return None
11390

@@ -117,7 +94,7 @@ def getPuissanceNominaleInKw(self, raw):
11794

11895
max_kw = getattr(self, "MAX_POWER_KW", 500)
11996

120-
# Cas énumération: on délègue à keepMaxValueIfEnum puis on formate.
97+
# enumeration case: we only want the max value and format it.
12198
if ";" in s:
12299
max_str = self.keepMaxValueIfEnum(s)
123100
if not max_str:
@@ -130,7 +107,7 @@ def getPuissanceNominaleInKw(self, raw):
130107
return None
131108
return f"{self._normalize_number(v)} kW"
132109

133-
# Cas valeur unique
110+
# case of only one value
134111
s_norm = s.lower().replace(",", ".")
135112
try:
136113
if s_norm.endswith("kw"):
@@ -142,7 +119,7 @@ def getPuissanceNominaleInKw(self, raw):
142119
v = v_w / 1000.0
143120
return f"{self._normalize_number(v)} kW"
144121

145-
# Sans unité
122+
# case without unit
146123
v = float(s_norm)
147124
if v > max_kw:
148125
# On suppose des watts => conversion en kW
@@ -154,73 +131,48 @@ def getPuissanceNominaleInKw(self, raw):
154131
def __init__(self, config, logger=None):
155132
Analyser_Merge_Point.__init__(self, config, logger)
156133
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)
198153

199154
self.init(
200155
"https://transport.data.gouv.fr/datasets/fichier-consolide-des-bornes-de-recharge-pour-vehicules-electriques/",
201156
"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")),
209159
Load_XY("Xlongitude", "Ylatitude"),
210160
Conflate(
211161
select=Select(
212-
types=["nodes", "ways"], tags={"amenity": "charging_station"}
213-
),
162+
types=["nodes", "ways"],
163+
tags={"amenity": "charging_station"}),
214164
conflationDistance=100,
215165
osmRef="ref:EU:EVSE",
216166
mapping=Mapping(
217-
static1={"amenity": "charging_station", "motorcar": "yes"},
167+
static1={
168+
"amenity": "charging_station",
169+
"motorcar": "yes"},
218170
static2={"source": self.source},
219171
mapping1={
220172
"operator": "nom_operateur",
221173
"network": "nom_enseigne",
222174
"owner": "nom_amenageur",
223-
"ref:EU:EVSE": "id_station_itinerance",
175+
"ref:EU:EVSE": "id_station_itinerance"
224176
},
225177
mapping2={
226178
"charging_station:output": lambda fields: self.getPuissanceNominaleInKw(
@@ -230,87 +182,20 @@ def __init__(self, config, logger=None):
230182
"operator:email": "contact_operateur",
231183
"start_date": "date_mise_en_service",
232184
"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",
245189
"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,
313200
},
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

Comments
 (0)