This commit is contained in:
Tykayn 2023-08-09 23:10:45 +02:00 committed by tykayn
parent cbe2ec28d2
commit a5ebecee00
190 changed files with 10074255 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
**/*/node_modules
/node_modules/
/coverage

View File

@ -0,0 +1,39 @@
# Conversion de jeux de données geojson en tags OSM
installation
```bash
npm i
npm i -g geojsontoosm
```
## Tout convertir faire d'un coup
Pour récupérer le jeu de données pour les bornes elec et convertir le geojson en fichier osm, lancer le script bash
```bash
bash refresh_data.sh
```
Export depuis overpass turbo dans OSM
https://overpass-turbo.eu/s/1yhY
## config
Configurer le filtre de département et les autres options dans convert_to_osm_tags.ts.
## utilisation
```bash
node convert_to_osm_tags.ts
```
résultat en json dans le dossier output.
La sortie est filtrée selon le mappage donné et la zone de code postal de la config.
Réalisé pour l'intégration des bornes elec.
# Ressources
Tableau de conversion de l'open data
https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques
# Roadmap
## bornes recharge elec IRVE
* ne pas mettre ref:EU:EVSE si la valeur vaut "non concerné"
* convertir les False en no
* enlever les source:date
* enlever les name

6
babel.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};

183
build_departments.ts Normal file
View File

@ -0,0 +1,183 @@
/**
build all files for departements from the dataset and the mapping engine
**/
const {exec} = require('child_process');
const execSync = require("child_process").execSync;
let min_department = 1;
const max_departement = 1
let enable_domtom = true;
// const max_departement = 95
function exec_command(command: string) {
console.log('=> command',
command
)
const result = execSync(command);
// convert and show the output.
console.log(result.toString("utf8"));
}
function build_department_geojson(department: string) {
let command = `ts-node convert_to_osm_tags.ts --department=${department}`;
console.log('command', command)
exec_command(command)
}
function convert_geojson_to_osm_for_department(department: string) {
let command = `geojsontoosm output/my_converted_data_set_filtered_zipcode_${department}.json > osm_output/bornes-irve-filetered-from-etalab-opendata_dep_${department}.osm`;
console.log('command', command)
exec_command(command)
}
for (let ii = min_department; ii <= max_departement; ii++) {
let departement = '' + ii
build_department_geojson(departement)
}
for (let ii = min_department; ii <= max_departement; ii++) {
let departement = '' + ii
convert_geojson_to_osm_for_department(departement)
}
// build_department_geojson('2A')
// convert_geojson_to_osm_for_department('2A')
// build_department_geojson('2B')
// convert_geojson_to_osm_for_department('2B')
if (enable_domtom) {
// départements corse et dom tom
let more_departements = ['2A', '2B'
, '971'
, '972'
, '973'
, '974'
, '975'
, '976']
more_departements.forEach((department => {
console.log(' mapping data for department ' + department)
let departement_string = '' + department
build_department_geojson(departement_string)
}))
more_departements.forEach((department => {
console.log('convert to osm ' + department)
let departement_string = '' + department
convert_geojson_to_osm_for_department(departement_string)
}))
}
/**
Numéro Départements Chef-lieu
01 Ain Bourg-en-Bresse
02 Aisne Laon
03 Allier Moulin
04 Alpes-de-Haute-Provence Digne
05 Hautes-Alpes Gap
06 Alpes-Maritimes Nice
07 Ardèche Privas
08 Ardennes Charleville-Mézières
09 Ariège Foix
10 Aube Troyes
11 Aude Carcassonne
12 Aveyron Rodez
13 Bouches-du-Rhône Marseille
14 Calvados Caen
15 Cantal Aurillac
16 Charente Angoulême
17 Charente-Maritime La Rochelle
18 Cher Bourges
19 Corrèze Tulle
21 Côte-d'Or Dijon
22 Côtes d'Armor Saint-Brieuc
23 Creuse Guéret
24 Dordogne Périgueux
25 Doubs Besançon
26 Drôme Valence
27 Eure Evreux
28 Eure-et-Loir Chartres
29 Finistère Quimper
30 Gard Nîmes
31 Haute-Garonne Toulouse
32 Gers Auch
33 Gironde Bordeaux
34 Hérault Montpellier
35 Ille-et-Vilaine Rennes
36 Indre Châteauroux
37 Indre-et-Loire Tours
38 Isère Grenoble
39 Jura Lons-le-Saunier
40 Landes Mont-de-Marsan
41 Loir-et-Cher Blois
42 Loire St-Étienne
43 Haute-Loire Le Puy
44 Loire-Atlantique Nantes
45 Loiret Orléans
46 Lot Cahors
47 Lot-et-Garonne Agen
48 Lozère Mende
49 Maine-et-Loire Angers
50 Manche St-
51 Marne Châlons-sur-Marne
52 Haute-Marne Chaumont
53 Mayenne Laval
54 Meurthe-et-Moselle Nancy
55 Meuse Bar-le-Duc
56 Morbihan Vannes
57 Moselle Metz
58 Nièvre Nevers
59 Nord Lille
60 Oise Beauvais
61 Orne Alençon
62 Pas-de-Calais Arras
63 Puy-de-Dôme Clermont-Ferrand
64 Pyrénées-Atlantiques Pau
65 Hautes-Pyrénées Tarbes
66 Pyrénées-Orientales Perpignan
67 Bas-Rhin Strasbourg
68 Haut-Rhin Colmar
69 Rhône Lyon
70 Haute-Saône Vesoul
71 Saône-et-Loire Mâcon
72 Sarthe Le Mans
73 Savoie Chambéry
74 Haute-Savoie Annecy
75 Paris Paris
76 Seine-Maritime Rouen
77 Seine-et-Marne Melun
78 Yvelines Versailles
79 Deux-Sèvres Niort
80 Somme Amiens
81 Tarn Albi
82 Tarn-et-Garonne Montauban
83 Var Toulon
84 Vaucluse Avignon
85 Vendée La Roche-sur-Yon
86 Vienne Poitiers
87 Haute-Vienne Limoges
88 Vosges Épinal
89 Yonne Auxerre
90 Territoire de Belfort Belfort
91 Essonne Evry
92 Hauts-de-Seine Nanterre
93 Seine-St-Denis Bobigny
94 Val-de-Marne Créteil
95 Val-D'Oise Pontoise
2A Corse-du-Sud Ajaccio
2B Haute-Corse Bastia
971 Guadeloupe Basse-Terre
972 Martinique Fort-de-France
973 Guyane Cayenne
974 La Réunion Saint-Denis
976 Mayotte Mamoudzou
**/

299
convert_to_osm_tags.ts Normal file
View File

@ -0,0 +1,299 @@
/**
* convertisseur de données de bornes de recharge électrique à partir de données Chargemap et open data Etalab
*/
import * as fs from 'fs'
import mappingConfigIRVE from './mappings/converters/configIRVE'
import mappingConfigIRVE_simple from './mappings/converters/mappingConfigIRVE_simple'
import mapping_engine from './mappings/engine'
import {BoundingBoxCoordinatesType, FeatureCollection} from "./mappings/mapping-config.type";
import utils from './mappings/utils'
const minimist = require('minimist')
const debugLog = utils.debugLog;
let use_mapping_engine = false
use_mapping_engine = true
let Mapping_engine = new mapping_engine(mappingConfigIRVE)
let mini_arguments: any = minimist(process.argv.slice(2))
// let sourceFilePathGeoJson = './etalab_data/small.json'
let sourceFilePathGeoJson = './etalab_data/all.json'
// let sourceFilePathGeoJson = './output/my_converted_data_set_filtered_zipcode_91.json'
// let sourceFilePathGeoJson = './output/my_converted_data_set_filtered_zipcode_91_small.json'
// wip filter
let filterOnBoundingBox = true
filterOnBoundingBox = false
let boundingBoxCoordinates: BoundingBoxCoordinatesType = {
xMin: 1.91,
xMax: 2.38,
yMin: 48.7,
yMax: 48.4,
}
let filterCoordinates = true
filterCoordinates = false
let enable_filter_on_department = true
enable_filter_on_department = false
let filterDepartment = 91
if (mini_arguments['department']) {
filterDepartment = mini_arguments['department']
enable_filter_on_department = true
}
if (mini_arguments['source']) {
sourceFilePathGeoJson = mini_arguments['source']
}
if (mini_arguments['engine']) {
use_mapping_engine = mini_arguments['engine']
}
let filterZipCode = new RegExp(`^${filterDepartment}`)
let filterZipCodeAdresse = new RegExp(` ${filterDepartment}`)
let filteredName = ''
if (enable_filter_on_department) {
filteredName = '_filtered_zipcode_' + filterDepartment
} else if (filterOnBoundingBox) {
filteredName = '_filtered_bbox_' + boundingBoxCoordinates.xMin + '-' + boundingBoxCoordinates.xMax + '_' + boundingBoxCoordinates.yMin + '-' + boundingBoxCoordinates.yMax
}
let pointCounterMax: number = 1000000
let limitConversionToFirstPoint: boolean = false
// limitConversionToFirstPoint = true
if (limitConversionToFirstPoint) {
pointCounterMax = 1
}
let defaultPropertiesOfPoint: any = {
'amenity': 'charging_station'
}
let converted_geo_json: any = {
type: 'FeatureCollection',
features: []
}
let output_folder = 'output';
/**
* crée un fichier dans le dossier par défaut, output
* @param fileName
* @param fileContent
*/
function writeFile(fileName: string, fileContent: any) {
debugLog('write file ', fileName)
return fs.writeFile(
`./${output_folder}/${fileName}`,
fileContent,
'utf8',
(err) => {
if (err) {
debugLog(`Error writing file: ${err}`)
} else {
debugLog(`File ${fileName} is written successfully!`)
}
}
)
}
/**
*
* @param sourceFilePath
* @param mapping
* @param pointCounterMax
* @param boundingBoxCoordinates
*/
function convertDataForIRVE(sourceFilePath: string, mapping: any, pointCounterMax: number, boundingBoxCoordinates: any) {
debugLog('convertDataForIRVE from ', sourceFilePath)
fs.readFile(sourceFilePath, 'utf8', function (err, data) {
let point_counter = 0
let feature_points_after_filter: any = []
if (err) {
return debugLog(err)
}
let data_transformed: FeatureCollection = JSON.parse(data)
// debug('data keys ', Object.keys(dataTransformed))
// debugLog('properties of point 0', data_transformed.features[0])
if (data_transformed.features) {
debugLog('data found, features:', data_transformed.features.length)
// find interesting list of points to use
let list_of_points: any = data_transformed.features
debugLog('listOfPoints.length', list_of_points.length)
/**
* filtering
* TODO: do it in the engine
*/
// for each point from the data source, filter if we take it or not
list_of_points.forEach((feature_point: any) => {
let regex_filter_test_result = true
if (enable_filter_on_department) {
debugLog('filtre sur les départements activé')
regex_filter_test_result = (
filterZipCode.test(feature_point.properties.consolidated_code_postal)
||
filterZipCodeAdresse.test(feature_point.properties.adresse_station)
)
} else {
debugLog('pas de filtre sur les départements')
}
if (filterOnBoundingBox) {
debugLog('filtre sur les coordonnées bounding box activé')
let x = feature_point.properties.coordonneesXY[0]
let xMin = boundingBoxCoordinates.xMin
let xMax = boundingBoxCoordinates.xMax
let yMin = boundingBoxCoordinates.yMin
let yMax = boundingBoxCoordinates.yMax
let y = feature_point.properties.coordonneesXY[1]
regex_filter_test_result = (
(x >= xMin && x <= xMax)
&&
(y >= yMin && y <= yMax)
)
} else {
debugLog('pas de filtre sur les coordonnées bounding box')
}
// TODO add filter offset max
// filter points depending on zipcode
if (regex_filter_test_result) {
feature_points_after_filter.push(feature_point)
debugLog(' +1 point', point_counter)
point_counter++
}
})
/**
* conversion
*/
debugLog(' after filtering, feature_points_after_filter number of points: ', feature_points_after_filter.length)
feature_points_after_filter.forEach((feature_point: any) => {
// debugLog('featurePoint.properties.consolidated_code_postal', feature_point.properties.consolidated_code_postal)
debugLog('convert : work on 1 point')
// debugLog('convert :featurePoint', feature_point)
let mapped_point: any = {}
if (use_mapping_engine) {
// debugLog('convert :using mapping engine on feature point'
// , feature_point
// )
mapped_point = Mapping_engine.mapElementFromConf(feature_point)
debugLog('mapped_point', mapped_point)
} else {
debugLog('convert :using simple converter on feature point', feature_point)
mapped_point = mapElementFromConfSimple(feature_point, mapping)
}
// debugLog('mapped_point one point', mapped_point)
if (mapped_point) {
converted_geo_json.features.push(mapped_point)
debugLog('convert : added one point to converted_geo_json')
} else {
debugLog('convert : !!! there is no map one point')
}
})
// output new geojson
debugLog('convert : convertedGeoJson.features.length', converted_geo_json.features.length)
// write file on disk
if (converted_geo_json.features.length) {
let fileNameToWrite = 'my_converted_data_set' + filteredName + '.json'
console.log('features: ', converted_geo_json.features.length)
debugLog('convert : write file ', fileNameToWrite)
writeFile(fileNameToWrite, JSON.stringify(converted_geo_json, null, 2))
} else {
console.log('convert : no writing of file, because there is no converted feature')
}
// console.log('convert : converted_geo_json output:', converted_geo_json.features)
return converted_geo_json
}
})
}
/**
* retuns the converted element from mapping config if present, null otherwise
*/
function mapElementFromConfSimple(featurePoint: any, mappingConfig: any) {
let mappingKeys = Object.keys(mappingConfig)
let featurePointPropertiesKeys = Object.keys(featurePoint.properties)
debugLog('keys', mappingKeys, featurePointPropertiesKeys)
let newProperties: any = defaultPropertiesOfPoint
// reinit properties of current point
let basePoint = Object.create(featurePoint)
basePoint.type = featurePoint.type
basePoint.geometry = featurePoint.geometry
basePoint.properties = newProperties
// apply new properties if found in mapping config
featurePointPropertiesKeys.forEach((pointKeyName: string) => {
if (mappingKeys.indexOf(pointKeyName) !== -1) {
// debugLog('found element', pointKeyName, '=>', mappingConfig[pointKeyName], 'value : ', featurePoint.properties[pointKeyName])
let convertedValue: any = ''
if (utils.isBooleanKey(pointKeyName)) {
let copyOfValue: any = '' + featurePoint.properties[pointKeyName]
if (typeof copyOfValue === typeof Object && copyOfValue.key_converted) {
copyOfValue = copyOfValue.key_converted
}
convertedValue = copyOfValue.toLowerCase() == 'true' ? 'yes' : 'no'
} else {
convertedValue = featurePoint.properties[pointKeyName]
}
if (convertedValue) {
let convertedKey: any = mappingConfig[pointKeyName]
newProperties[convertedKey] = convertedValue
}
}
})
debugLog('basePoint', basePoint)
return basePoint
}
if (use_mapping_engine) {
debugLog(' - using mapping engine')
debugLog(' - pointCounterMax', pointCounterMax)
Mapping_engine.setConfig(mappingConfigIRVE)
convertDataForIRVE(sourceFilePathGeoJson, mappingConfigIRVE, pointCounterMax, boundingBoxCoordinates)
} else {
let mappingConfigIRVE = mappingConfigIRVE_simple
convertDataForIRVE(sourceFilePathGeoJson, mappingConfigIRVE, pointCounterMax, boundingBoxCoordinates)
}

File diff suppressed because it is too large Load Diff

4929
data_other/export.geojson Normal file

File diff suppressed because it is too large Load Diff

204423
data_other/export.json Normal file

File diff suppressed because it is too large Load Diff

1121
data_other/issues.kml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
import MappingConfigType from "../../mappings/mapping-config.type";
/**
* configurations de mapping pour les cas de tests
*/
export const mappingRemoveAll: MappingConfigType = {
config_name: 'testing config',
config_author: 'tykayn <contact@cipherbliss.com>',
default_properties_of_point: {
'amenity': 'charging_station'
},
tags: {
nom_amenageur: {
key_converted: 'autre_nom_amenageur',
conditional_values: {
'Accessibilité inconnue': {
ignore_this_data: true, // ne pas ajouter de tag si la valeur est égale à Accessibilité inconnue.
},
}
}
}
}
export const mappingIgnore: MappingConfigType = {
config_name: 'testing config',
config_author: 'tykayn <contact@cipherbliss.com>',
default_properties_of_point: {
'amenity': 'charging_station'
},
tags: {
nom_amenageur: {
ignore_this_data: true,
}
}
}

View File

@ -0,0 +1,21 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
4.822159,
45.635079
]
},
"properties": {
"nom_amenageur": "ELECTRA",
"siren_amenageur": "891624884",
"consolidated_commune": "S\u00e9r\u00e9zin-du-Rh\u00f4ne",
"consolidated_is_lon_lat_correct": true
}
}
]
}

315
dataset_info.md Normal file
View File

@ -0,0 +1,315 @@
# info sur les jeux de données
D'après le jeu de données Etalab
## liste des 310 opérateurs
270 AGENCY
2Ed Coutances
2F Production
ABSOLUT CONCEPT
Acelec Charge
advenir@zeborne.com
Aeroports de lyon
Allego
ALLENERGIES
alterna energie
ALU GRANON
Ambroise Avocat
ANYOS
AQUA LOISIRS
AREA Tech
ART DECO FINITION
arteco44
ATELIERS PROVENCE LOISIRS
Atlante | FR*ATL
ATRACHATA
Autel Netherlands B.V. | FR*AUT
Automobile de l'Est
AUTORECHARGE
AUTORECHARGE
AUTORECHARGE SAS
Avomarks
Bastide beaudinard & tours (BBT)
BAUDUCEL
Bénédictines du Sacré-Coeur de Montmartre
BH RESTAURATION
BIARS DISTRIBUTION
BORNECO
Borneco | FR*BHM
Bornevo
Bornevo Connect
Bouygues Energies et Services
BOUYGUES ENERGIES ET SERVICES
box
Camping des graniers
CAP EMPLOI
CAR2PLUG
CHAPITEAUX SERVICE
ChargePoint
Chargepoint
CHARGEPOLY
CHARRIERE DISTRIBUTION
CHATEAU DE RONZIERE
COMMUNAUTE DE COMMUNE LE DOURDANNAIS EN HUREPOIX (CCDH)
contact@autorecharge.fr
COPRODEX
Daltoner Avranches
Daltoner Caen
DALTONER CHERBOURG
Daltoner Granville
Daltoner Vire
DIDIER CHARTON-VACHET
Dropnplug
e-nergyze
E-TOTEM
E-totem
Easycharge services
Ecophi mobility
EcoPhi mobility
EDF
EDFRAY
EGE NOEL BERANGER
EGSM
EIZMENDI TRAITEUR EVENEMENTS
Ekoplug
ELEC eCONNECT
ELECTRA
ELECTRIC 55 CHARGING
Electriox Groupe
electromaps
ELECTROMAPS
Electromaps
ELEK BORDEAUX
ENERGEM
ENERGIE Eure-et-Loir
ENERGIE EURE-ET-LOIR
ENNESSER ET FILS
ENTREPRISE ADAM
ESPACE AUTO COURNON
Est Auto
EURO TAXI LINE
EV MAP SAS
EVBOX
EVERON
EVzen (SMEG Développement)
evzen (SMEG Développement)
evZen | FR*EVZ
F.B. AUTOMOBILES
Festilight
Freshmile
FRESHMILE
freshmile
FReshmile
Freshmile SAS
GABMAG17
GABORIT BOCAGE SERVICES
Gamba et Rota
GARAGE HENRY
garage Henry herve
Garage lefebvre
GEDIBOIS BATI COLMAN
GENE ELEC 35
GF3e
Golf de La Wantzenau
Green Diffusion
Green Technologie
GREEN TECHNOLOGIE
Green To Wheel
GreenYellow | FR*GYM
GROFF SAS
GROUPE COURTOIS SOCOHY
GROUPE LGE
GROUPE LGE SOCIETE AUTOPLUG
Grunzke Beate
Guerin
H alu concept
HABT
HAEFELI
HERVE THERMIQUE
HFOOD PESSAC
HFOOD VILLENAVE
Hostellerie
Hotel Le Moulin
Hôtel MACCHI
Hôtel Restaurant Hubert Kieffer
ICS Scgilthigheim
IFERRO
INOUID
IONITY
Ispo france
IXINA Le Cres
IXINA Saint Jean de Védas
ixina Villeneuve-lès-Béziers
Izivia
JAV INVESTISSEMENT
jmd
JONNARD LES ISSAMBRES
Kallista BDR
KIEHL
Kotelon
LA CONCIERGERIE D'ISA.
La dilettante
La jabotte
La jardinerie d'aveze sarl
LA PRAIRIE
Lacotte
Lacotte Pierre
LANGON DISTRIBUTION
Last Mile Solutions
LE BISTRO D'HUGO
Le Capelan
Le Grand Large
Le Manoir de l'Isle
le Relais
LE REVE DE JANINE
Leclerc Millau
LEGA
LEGELEUX
Leroux Damien
Les jardins maraichers des bords de rance
LIDL, Nicolas Barbarin
LMS Informatique
LUMI'IN
M. Yannick PIERRE
M.A.J.U.
ma borne auto
ma Borne Auto
MABORNEAUTO
MAS DES OLIVES
MAS DU TERME
MAS GALOFFRE
Masseria
MEA ENERGIES
MEDIODENT
Mickael Auto
MOBELEC
Modulo
MODULO
Modulo énergies
MONTA
MOVIVE_Izivia
NEXTENEO
NM SECURELEC
NON CONCERNE
Non concerné
non concerné
Normatech
Normatech Lodmi
NVH
NW IECharge
OCR MAINTENANCE ELECTRONIQUE
PAS DITINERANCE
Pascal Chene
Perrin
perrin
PHARMACIE DE HUNDLING
Pilotage Maritime
PLAGECO DISTRIBUTION
Polybati
Prodici
ProperPhi
Provibat
PROVIRIDIS
Proviridis | FR*PVD
PTBG et associés
QoWatt
R3
Ramsay Pole Lille métropole
RechargerMonAuto
REGIE MUNICIPALE D'ELECTRICITE DE LOOS
Rencontre-handi
REVE
RICOME ET SADOUL AXA FRANCE
RONALEV
Royal Champagne
RSDA mobility
SA FOOTBALL CLUB DES GIRONDINS DE BORDEAUX
sa les broyers
Sanou électricité
SAP LABS FRANCE
SARL BEAUDRE BAUDOT
SARL JUMO
SARL LAFOURCADE
SARL LES BAINS DE ROYAN
SARL VAHE
SAS CHATEAU DE MEMANAT
SAS DE L'AILETTE
sas e-motum
SAS Lujasy
SAS Miodis
SAS Sabo
SATUJO
SCI LA COLLINE
SCI LA GRANGE DESSOUS
SCI LES RUISSEAUX
SCI Lounapiou
SCI NOKI
SCI OLYMPE
SCP ACANTHE DRIMARACCI
SDC CENTRE MEDICAL ARTZAMENDI
SDC ORDINAL
SECAL
Securecharge
See You Sun
SELARL PHARMACIE CEVENOLE
Séolis
SGA Industries
SIEGE 27
SIPECC
SNAM GROUPE
SNER RHONE-ALPES
société La Clérine
Société LEVAROY, Monsieur LEROY
Societe moderne d'isolation
Société Sigma Tec
Société SIPECC
Société Y
Sodetrel
SOLIDARAUTO 49
SOREGIES
SPBR1
SPIE CITYNETWORKS
STATIONS-E
Sud Camargue
Sud Hotel
TANAY Electricité
Technic Elec
themis
Thibal Distribution
TISSERANT
total énergie
Total marketing france
TotalEnergies Charging Services
TotalEnergies Marketing France
ubitricity
UBITRICITY GMBH
Vegetalis
Vigot
Ville de Riquewihr
Vincent
Virta
VIRTA
Volta Charging
WAAT
WAAT SAS | FR*W10
WAAT SAS | FR*W11
WAAT SAS | FR*WA1
WAAT SAS | FR*WA3
WAAT SAS | FR*WA4
WAAT SAS | FR*WA5
WAAT SAS | FR*WA6
WAAT SAS | FR*WA8
WAAT SAS | FR*WA9
WAAT SAS | FR*WAT
WattzHub | FR*SMI
web services advenir
Wedom
WeDoM
WeDoM.io
WeeCharge
WICKER TP
ZEBORNE
ZEborne
ZEENCO
Zen Construction

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

125
doc/irve_puissances.md Normal file
View File

@ -0,0 +1,125 @@
# domaines de données IRVE
## puissance_nominale
quelle pagaille:
225
150
50
300
22
24
18
350
25
21
7
48
38
63
320
160
125
43
2
11
3
200
175
6
20
23
45
17
44
56
325
90
75
120
4
36
180
54
7.4
42
12
15
60
100
30
210
126
40
9
70
80
360
124
64
115
62
22.00
22.0
0.0
50.00
12
47
24.00
7.00
7.0
5.9
71708
131524
49521
0
19
300000
22080
50000
63000
90000
60000
3.4
5
122
72
18.00
43.00
3.22
3.00
11.00
230
400
110
22
2.3
27
26
3.7
62500
22.08
7.36
11.04
1.7
14
22000
7000
3000
4.6
32
2859660
60973
5.5
12
175.00
22
22
100.00
6.9
240
149
16

44877
etalab_data/all.csv Normal file

File diff suppressed because it is too large Load Diff

2782317
etalab_data/all.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2089090
etalab_data/etalab.json Normal file

File diff suppressed because it is too large Load Diff

67
etalab_data/latest.json Normal file
View File

@ -0,0 +1,67 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
4.822159,
45.635079
]
},
"properties": {
"nom_amenageur": "ELECTRA",
"siren_amenageur": "891624884",
"contact_amenageur": "help@electra.com",
"nom_operateur": "ELECTRA",
"contact_operateur": "help@electra.com",
"telephone_operateur": "",
"nom_enseigne": "ELECTRA",
"id_station_itinerance": "FRELCPSDRPG",
"id_station_local": "",
"nom_station": "S\u00e9r\u00e9zin-du-Rh\u00f4ne - Peugeot",
"implantation_station": "Station d\u00e9di\u00e9e \u00e0 la recharge rapide",
"adresse_station": "12 chemin d\u00e9partemental 12, Peugeot 69360 S\u00e9r\u00e9zin-du-Rh\u00f4ne",
"code_insee_commune": "69294",
"coordonneesXY": "[4.82215900,45.63507900]",
"nbre_pdc": "8",
"id_pdc_itinerance": "FRELCECURS",
"id_pdc_local": "",
"puissance_nominale": "225",
"prise_type_ef": "false",
"prise_type_2": "false",
"prise_type_combo_ccs": "true",
"prise_type_chademo": "false",
"prise_type_autre": "false",
"gratuit": "false",
"paiement_acte": "true",
"paiement_cb": "true",
"paiement_autre": "true",
"tarification": "",
"condition_acces": "Acc\u00e8s libre",
"reservation": "true",
"horaires": "24/7",
"accessibilite_pmr": "Accessibilit\u00e9 inconnue",
"restriction_gabarit": "Inconnu",
"station_deux_roues": "false",
"raccordement": "Direct",
"num_pdl": "N/A",
"date_mise_en_service": "2022-10-27",
"observations": "T\u00e9l\u00e9charger l'application ELECTRA pour r\u00e9server et payer sur go-electra.com",
"date_maj": "2023-07-29",
"cable_t2_attache": "",
"last_modified": "2023-07-29T03:05:24.360000+00:00",
"datagouv_dataset_id": "623ca46c13130c3228abd018",
"datagouv_resource_id": "e9bb3424-77cd-40ba-8bbd-5a19362d0365",
"datagouv_organization_or_owner": "electra",
"consolidated_longitude": 4.822159,
"consolidated_latitude": 45.635079,
"consolidated_code_postal": "69360",
"consolidated_commune": "S\u00e9r\u00e9zin-du-Rh\u00f4ne",
"consolidated_is_lon_lat_correct": true,
"consolidated_is_code_insee_verified": true
}
}
]
}

4
etalab_data/small.csv Normal file
View File

@ -0,0 +1,4 @@
nom_amenageur,siren_amenageur,contact_amenageur,nom_operateur,contact_operateur,telephone_operateur,nom_enseigne,id_station_itinerance,id_station_local,nom_station,implantation_station,adresse_station,code_insee_commune,coordonneesXY,nbre_pdc,id_pdc_itinerance,id_pdc_local,puissance_nominale,prise_type_ef,prise_type_2,prise_type_combo_ccs,prise_type_chademo,prise_type_autre,gratuit,paiement_acte,paiement_cb,paiement_autre,tarification,condition_acces,reservation,horaires,accessibilite_pmr,restriction_gabarit,station_deux_roues,raccordement,num_pdl,date_mise_en_service,observations,date_maj,cable_t2_attache,last_modified,datagouv_dataset_id,datagouv_resource_id,datagouv_organization_or_owner,consolidated_longitude,consolidated_latitude,consolidated_code_postal,consolidated_commune,consolidated_is_lon_lat_correct,consolidated_is_code_insee_verified
ELECTRA,891624884,help@electra.com,ELECTRA,help@electra.com,,ELECTRA,FRELCPBROHI,,Bron - Hôtel Ibis Lyon Est,Station dédiée à la recharge rapide,36 avenue du Doyen Jean Lépine 69500 Bron,69029,"[4.90415400,45.74800500]",4,FRELCE2JW9,,225,false,false,true,false,false,false,true,true,true,,Accès libre,true,24/7,Accessibilité inconnue,Inconnu,false,Direct,N/A,2023-05-04,Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com,2023-08-06,,2023-08-06T03:05:25.841000+00:00,623ca46c13130c3228abd018,e9bb3424-77cd-40ba-8bbd-5a19362d0365,electra,4.904154,45.748005,69500,Bron,True,True
ELECTRA,891624884,help@electra.com,ELECTRA,help@electra.com,,ELECTRA,FRELCPBLOHM,,Blotzheim - Hôtel Mercure Bâle Mulhouse Aéroport,Station dédiée à la recharge rapide,3 rue de l'industrie 68730 Blotzheim,68042,"[7.50290400,47.60821400]",8,FRELCEXY9P,,225,false,false,true,false,false,false,true,true,true,,Accès libre,true,24/7,Accessibilité inconnue,Inconnu,false,Direct,N/A,2022-09-22,Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com,2023-08-06,,2023-08-06T03:05:25.841000+00:00,623ca46c13130c3228abd018,e9bb3424-77cd-40ba-8bbd-5a19362d0365,electra,7.502904,47.608214,68730,Blotzheim,True,True
ELECTRA,891624884,help@electra.com,ELECTRA,help@electra.com,,ELECTRA,FRELCPSMCLE,,Saint-Magne-de-Castillon - E.Leclerc,Station dédiée à la recharge rapide,2 chemin de Perrin 33350 Saint-Magne-de-Castillon,33437,"[-0.06340700,44.85401900]",4,FRELCEEEAW,,150,false,false,true,false,false,false,true,true,true,,Accès libre,true,24/7,Accessibilité inconnue,Inconnu,false,Direct,N/A,2023-04-28,Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com,2023-08-06,,2023-08-06T03:05:25.841000+00:00,623ca46c13130c3228abd018,e9bb3424-77cd-40ba-8bbd-5a19362d0365,electra,-0.063407,44.854019,33350,Saint-Magne-de-Castillon,True,True
1 nom_amenageur siren_amenageur contact_amenageur nom_operateur contact_operateur telephone_operateur nom_enseigne id_station_itinerance id_station_local nom_station implantation_station adresse_station code_insee_commune coordonneesXY nbre_pdc id_pdc_itinerance id_pdc_local puissance_nominale prise_type_ef prise_type_2 prise_type_combo_ccs prise_type_chademo prise_type_autre gratuit paiement_acte paiement_cb paiement_autre tarification condition_acces reservation horaires accessibilite_pmr restriction_gabarit station_deux_roues raccordement num_pdl date_mise_en_service observations date_maj cable_t2_attache last_modified datagouv_dataset_id datagouv_resource_id datagouv_organization_or_owner consolidated_longitude consolidated_latitude consolidated_code_postal consolidated_commune consolidated_is_lon_lat_correct consolidated_is_code_insee_verified
2 ELECTRA 891624884 help@electra.com ELECTRA help@electra.com ELECTRA FRELCPBROHI Bron - Hôtel Ibis Lyon Est Station dédiée à la recharge rapide 36 avenue du Doyen Jean Lépine 69500 Bron 69029 [4.90415400,45.74800500] 4 FRELCE2JW9 225 false false true false false false true true true Accès libre true 24/7 Accessibilité inconnue Inconnu false Direct N/A 2023-05-04 Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com 2023-08-06 2023-08-06T03:05:25.841000+00:00 623ca46c13130c3228abd018 e9bb3424-77cd-40ba-8bbd-5a19362d0365 electra 4.904154 45.748005 69500 Bron True True
3 ELECTRA 891624884 help@electra.com ELECTRA help@electra.com ELECTRA FRELCPBLOHM Blotzheim - Hôtel Mercure Bâle Mulhouse Aéroport Station dédiée à la recharge rapide 3 rue de l'industrie 68730 Blotzheim 68042 [7.50290400,47.60821400] 8 FRELCEXY9P 225 false false true false false false true true true Accès libre true 24/7 Accessibilité inconnue Inconnu false Direct N/A 2022-09-22 Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com 2023-08-06 2023-08-06T03:05:25.841000+00:00 623ca46c13130c3228abd018 e9bb3424-77cd-40ba-8bbd-5a19362d0365 electra 7.502904 47.608214 68730 Blotzheim True True
4 ELECTRA 891624884 help@electra.com ELECTRA help@electra.com ELECTRA FRELCPSMCLE Saint-Magne-de-Castillon - E.Leclerc Station dédiée à la recharge rapide 2 chemin de Perrin 33350 Saint-Magne-de-Castillon 33437 [-0.06340700,44.85401900] 4 FRELCEEEAW 150 false false true false false false true true true Accès libre true 24/7 Accessibilité inconnue Inconnu false Direct N/A 2023-04-28 Télécharger l'application ELECTRA pour réserver et payer sur go-electra.com 2023-08-06 2023-08-06T03:05:25.841000+00:00 623ca46c13130c3228abd018 e9bb3424-77cd-40ba-8bbd-5a19362d0365 electra -0.063407 44.854019 33350 Saint-Magne-de-Castillon True True

17
etalab_data/small.json Normal file
View File

@ -0,0 +1,17 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
2.2335179, 48.6973801
]
},
"properties": {
"accessibilite_pmr":"Mo-Fr 08:30-12:00,Mo-Fr 14:00-19:00,Sat 09:00-18:30"
}
}
]
}

8
get_datasets.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
# get the updated geojson
wget https://www.data.gouv.fr/fr/datasets/r/7eee8f09-5d1b-4f48-a304-5e99e8da1e26 -P ./etalab_data -O ./etalab_data/all.json
wget https://www.data.gouv.fr/fr/datasets/r/8d9398ae-3037-48b2-be19-412c24561fbb -P ./etalab_data -O ./etalab_data/all.csv
# https://www.data.gouv.fr/fr/datasets/r/8d9398ae-3037-48b2-be19-412c24561fbb pour le jeu de données irve schema v2, non utilisé dans ce script
# filter its tags
echo "refresh de la data"

199
jest.config.ts Normal file
View File

@ -0,0 +1,199 @@
/**
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/
import type {Config} from 'jest';
const config: Config = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/tmp/jest_rs",
// Automatically clear mock calls, instances, contexts and results before every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// The default configuration for fake timers
// fakeTimers: {
// "enableGlobally": false
// },
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "mjs",
// "cjs",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
// preset: undefined,
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state before every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state and implementation before every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
// testEnvironment: "jest-environment-node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
};
export default config;

2780767
latest.json Normal file

File diff suppressed because it is too large Load Diff

1
main.ts Normal file
View File

@ -0,0 +1 @@
console.log('hello mapper')

126
make_variance_from_csv.ts Normal file
View File

@ -0,0 +1,126 @@
/**
prendre un CSV,
examiner toutes les colonnes et leurs valeurs,
garder en mémoire les valeurs uniques de chaque colonne
faire un nouveau csv qui ne montre que les valeurs uniques pour chacune des colonnes
et qui compte le nombre de valeurs
**/
import utils from './mappings/utils'
import {parse} from 'csv'
const fs = require('fs')
interface VarianceType {
[key: string]: Array<string>
}
let csv_content = 'variance de dataset\n';
let separator = ';';
// let columns_headings = [];
let data_variance: VarianceType = {};
const inputPath = './etalab_data/all.csv'
// const inputPath = './etalab_data/small.csv'
let columns_headings: Array<string> = [];
let lines_count = 0;
let longest_variance_count = 0;
console.log('open file ', inputPath)
fs.readFile(inputPath, function (err: any, fileData: any) {
if (err) {
throw new Error(err)
} else {
parse(fileData, {columns: false, trim: true}, function (err: any, rows: any) {
// Your CSV data is in an array of arrays passed to this callback as rows.
console.log('line ', lines_count)
rows.forEach((row: Array<any>) => {
if (lines_count === 0) {
// console.log('elem', row)
row.forEach((value: string) => {
// console.log('value', value)
columns_headings.push(value)
data_variance[value] = []
})
console.log('columns_headings.length', columns_headings.length)
lines_count++
} else {
// lignes suivantes
let column_index = 0;
row.forEach((value: string) => {
value = value.trim()
// dans chaque colonne, vérifier que la valeur n'est pas déjà présente dans les index de variance
// si la valeur est nouvelle, l'ajouter
if (data_variance[columns_headings[column_index]].indexOf(value) < 0) {
data_variance[columns_headings[column_index]].push(value)
if (
data_variance[columns_headings[column_index]].length > longest_variance_count
) {
longest_variance_count = data_variance[columns_headings[column_index]].length
}
}
column_index++
})
lines_count++
}
})
console.log('longest_variance_count', longest_variance_count)
utils.writeFile('variance.csv', writeCSVVariance())
// console.log('data_variance', data_variance)
})
}
console.log('parsing done')
// console.log('data_variance', data_variance)
})
/**
* écrit un csv avec les données de variance du dataset donné
*/
function writeCSVVariance() {
let csv_content = ';variance de ' + inputPath + ';' + new Date() + '\n'
let columns = Object.keys(data_variance);
// add headings
columns_headings.forEach((heading: string) => {
csv_content = csv_content + separator + heading
})
csv_content = csv_content + '\n'
// add max length of variance for each column
let ii = 0
columns.forEach((column: string) => {
// console.log('column', column, data_variance[column].length)
csv_content = csv_content + separator + data_variance[column].length
ii++
})
csv_content = csv_content + '\n\n'
// add content of values
for (let ii = 0; ii < longest_variance_count; ii++) {
csv_content = csv_content + '\n'
columns.forEach((column: any) => {
if (ii < data_variance[column].length) {
let currentValue = data_variance[column][ii]
csv_content = csv_content + separator + currentValue
} else {
csv_content = csv_content + separator
}
})
}
// console.log('csv_content', csv_content)
return csv_content;
}

View File

@ -0,0 +1,174 @@
/**
* plan de conversion des clés du jeu de données vers les tags OSM
* détail dans le tableau
* https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques
*/
import MappingConfigType from "../mapping-config.type";
const MappingIRVE: MappingConfigType = {
config_name: "IRVE config",
config_author: "tykayn <contact@cipherbliss.com>",
default_properties_of_point: {
'amenity': 'charging_station'
},
source: {
geojson_path: "etalab_data/all.json",
url: 'https://www.data.gouv.fr/fr/datasets/r/7eee8f09-5d1b-4f48-a304-5e99e8da1e26'
},
/**
* select only certain points from the source
*/
filters: {
enable_coordinates_filter: false,
enable_properties_filter: true,
// add only geojson points who are found having this regex in the zipcode properties
properties: {
consolidated_code_postal: '^[76|27]'
},
bounding_box: [
{}
]
},
add_not_mapped_tags_too: false,
tags: {
// ******* nombres
nbre_pdc: 'capacity',
// ******* textes
amenity: 'amenity', // conserver le tag de base
capacity: 'capacity', // conserver le tag de base
nom_amenageur: 'operator',
siren_amenageur: 'owner:ref:FR:SIREN',
nom_operateur: 'operator',
telephone_operateur: 'phone',
contact_operateur: 'email', // ici, on souhaite convertir la clé contact_operateur=bidule en email=bidule
// id_station_itinerance: 'ref:EU:EVSE',
id_station_local: 'ref',
gratuit: {
key_converted: 'fee',
convert_to_boolean_value: true,
},
paiement_acte:
{
key_converted: 'authentication:none',
convert_to_boolean_value: true, // convertit en yes ou no
},
reservation: {
convert_to_boolean_value: true, // convertit en yes ou no
},
// observations: 'note',
// nom_station: 'name',
nom_enseigne: 'network',
// ******* dates
date_mise_en_service: 'start_date',
// date_maj: 'source:date',
// ******** champs booléens
cable_t2_attache:
{
key_converted: 'socket:type2_cable',
// socket:type2_cable vaut 1 dans OSM si vrai
truthy_value: '1',
ignore_if_falsy: true,
}
,
prise_type_ef: {
key_converted: 'socket:typee',
ignore_if_falsy: true,
convert_to_boolean_value: true,
},
prise_type_2: {
key_converted: 'socket:type2',
ignore_if_falsy: true,
convert_to_boolean_value: true,
},
prise_type_combo_ccs: {
key_converted: 'socket:type2_combo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
},
prise_type_chademo: {
key_converted: 'socket:chademo',
ignore_if_falsy: true,
convert_to_boolean_value: true,
},
// ******** champs plus complexes
horaires: 'opening_hours', // déjà au bon format
// accessibilite_pmr: 'wheelchair',
paiement_cb: {
key_converted: 'payment:credit_cards',
// ignore_if_falsy: true,
convert_to_boolean_value: true,
},
// accessibilite_pmr: {
// key_converted: "wheelchair",
// conditional_values: {
// "Accessibilité inconnue": {
// // value_converted: "",
// ignore_this_data: true, // ne pas ajouter de tag si la valeur est égale à Accessibilité inconnue.
// // transform_function : (original_value) => original_value.toLowerCase(),
// },
// "Accessible mais non réservé PMR": {
// value_converted: "yes"
// },
// "Réservé PMR": {
// value_converted: "yes"
// },
// "Non accessible": {
// value_converted: "no"
// },
// "Mo-Fr 08:30-12:00,Mo-Fr 14:00-19:00,Sat 09:00-18:30": {
// value_converted: "Mo-Fr 08:30-12:00,Mo-Fr 14:00-19:00,Sat 09:00-18:30"
// },
// "24/7": {
// value_converted: ""
// }
station_deux_roues: {
remove_original_key: true,
conditional_values: {
// ajout de trois tags si la valeur est yes
"yes": {
tags_to_add: [
{bicycle: "yes"},
{scooter: "yes"},
{motorcar: "no"},
]
}
}
}
// TODO gestion des puissances de bornes
// avec une fonction de transformation des valeurs
// parmi le domaine du jeu de données
// nécessite une clé conditionnelle à la valeur true d'autres clés converties.
// c'est compliquay.
},
}
// "nom_amenageur": "ELECTRA",
// "siren_amenageur": "891624884",
// "consolidated_commune": "S\u00e9r\u00e9zin-du-Rh\u00f4ne",
// "consolidated_is_lon_lat_correct": true,
// "cable_t2_attache": "True"
// "goal": "jeu de données pour tester la mapping engine",
// "prise_type_2": "yes",
// "station_deux_roues": "yes",
// "accessibilite_pmr": "Non accessible",
// "amenity": "charging_station",
// "capacity": 12,
// "reservation": "False",
// "nom_amenageur": "Bob Lenon",
// "siren_amenageur": "12345678",
// "socket:typee": "False",
// "prise_type_combo_ccs": "no",
// "fee": "no",
// "authentication:none": "yes"
export default MappingIRVE;

View File

@ -0,0 +1,45 @@
/**
* plan de conversion des clés du jeu de données vers les tags OSM
* détail dans le tableau
* https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques
*/
const mappingIRVE:any = {
// ******* nombres
nbre_pdc: 'capacity',
amenity: 'amenity', // conserver le tag de base
capacity: 'capacity', // conserver le tag de base
nom_amenageur: 'operator',
siren_amenageur: 'owner:ref:FR:SIREN',
nom_operateur: 'operator',
telephone_operateur: 'phone',
// ici, on souhaite convertir la clé contact_operateur=bidule en email=bidule
contact_operateur: 'email',
id_station_itinerance: 'ref:EU:EVSE',
id_station_local: 'ref',
gratuit: 'fee',
paiement_acte: 'authentication:none',
reservation: 'reservation',
observations: 'note',
nom_station: 'name',
nom_enseigne: 'network',
// ******* dates
date_mise_en_service: 'start_date',
date_maj: 'source:date',
// ******** champs booléens
prise_type_ef: 'socket:typee',
prise_type_2: 'socket:type2',
prise_type_combo_ccs: 'socket:type2_combo',
prise_type_chademo: 'socket:chademo',
// ******** champs plus complexes
horaires: 'opening_hours', // déjà au bon format
}
export default mappingIRVE;

326
mappings/engine.ts Normal file
View File

@ -0,0 +1,326 @@
import custom_utils from './utils'
import MappingConfigType from "./mapping-config.type";
const {debugLog} = custom_utils
let listOfBooleanKeys = [
"prise_type_ef",
"prise_type_2",
"prise_type_combo_ccs",
"prise_type_chademo",
"gratuit",
"paiement_acte",
"paiement_cb",
"cable_t2_attache"
]
export default class {
mapping_config: any = {}
constructor(mappingConfig: MappingConfigType) {
this.setConfig(mappingConfig)
}
setConfig(mappingConfig: MappingConfigType) {
this.mapping_config = mappingConfig
}
mapFeaturePoint(featurePointGeoJson: any) {
let geoJSONConvertedPoint: any = {}
geoJSONConvertedPoint.properties = {...this.mapping_config.default_properties_of_point}
geoJSONConvertedPoint.type = featurePointGeoJson.type
geoJSONConvertedPoint.geometry = featurePointGeoJson.geometry
// let props = featurePointGeoJson.properties
// props.forEach((key, value) => {
//
// })
return geoJSONConvertedPoint
}
/**
* TODO convert to mapping config property to transform_truthy
* @param pointKeyName
* @returns {boolean}
*/
isBooleanKey(pointKeyName: string): boolean {
return listOfBooleanKeys.indexOf(pointKeyName) !== -1
}
truthyValues = ['true', 'True', 'TRUE', '1', 'yes', 1]
falsyValues = ['false', 'False', 'FALSE', '0', 'no', 0]
/**
* reduce number of features
* @param offsetCount
* @param listOfFeatures
*/
filterFeaturesByOffset(offsetCount: number, listOfFeatures: any): Array<any> {
let filteredList = listOfFeatures
// TODO
return filteredList
}
// filterFeaturesByPropertyRegex(bboxConfig:any, listOfFeatures:any) {
// debugLog('bboxConfig', bboxConfig)
// let filteredList = listOfFeatures
// // TODO
// return filteredList
// }
filterFeaturesByPropertyRegex(propertyName: string, criteriaRegex: any, listOfFeatures: any) {
let filteredList = listOfFeatures.filter((feature: any) => {
return criteriaRegex.test(feature?.properties[propertyName])
})
return filteredList
}
/**
* retuns the converted element from mapping config if present, null otherwise
*/
mapElementFromConf(featurePoint: any): any {
// debugLog('mapElementFromConf: mapElementFromConf', featurePoint)
if (!this.mapping_config) {
throw new Error('no config was loaded in the mapping engine. use setConfig(my_mapping_config) on this instance of mapping engine before using this.')
}
debugLog('mapElementFromConf: config_name', this.mapping_config.config_name)
let mappingKeys = Object.keys(this.mapping_config.tags)
let featurePointPropertiesKeys = Object.keys(featurePoint.properties)
debugLog('mapElementFromConf: ============= keys mappingKeys:', this.mapping_config.tags.length, mappingKeys.length)
debugLog('mapElementFromConf: ============= keys featurePointPropertiesKeys :', featurePoint.properties.length, featurePointPropertiesKeys.length)
let newProperties = {...this.mapping_config.default_properties_of_point}
// reinit properties of current point
let basePoint = Object.create(featurePoint)
basePoint.type = featurePoint.type
basePoint.geometry = featurePoint.geometry
basePoint.properties = {...this.mapping_config.default_properties_of_point}
// apply new properties if found in mapping config
featurePointPropertiesKeys.forEach(pointKeyName => {
debugLog('mapElementFromConf: convert', pointKeyName)
this.convertProperty(pointKeyName, mappingKeys, featurePoint, newProperties)
})
basePoint.properties = newProperties
// debugLog('mapElementFromConf: basePoint', basePoint)
return basePoint
}
/**
* convertit une propriété en une autre selon la config de mapping
* @param pointKeyName
* @param mappingKeys
* @param featurePoint
* @param newProperties
*/
convertProperty(pointKeyName: string, mappingKeys: any, featurePoint: any, newProperties: any) {
let originalValue = featurePoint.properties[pointKeyName]
let mappingValueObject: any = '';
if (mappingKeys.indexOf(pointKeyName) > 0) {
mappingValueObject = this.mapping_config.tags[pointKeyName]
debugLog('convertProperty: mappingValueObject ', mappingValueObject)
}
debugLog(' ------ convertProperty: pointKeyName', pointKeyName)
// debugLog('convertProperty: mappingKeys', mappingKeys)
if (this.mapping_config.add_not_mapped_tags_too && (mappingKeys.indexOf(pointKeyName) === -1)) {
/**
* add all unmapped tags is enabled
*/
newProperties[pointKeyName] = originalValue;
} else {
/**
* only use existing keys
*/
if (mappingKeys.indexOf(pointKeyName) > 0) {
let valueConvertedFromMapping = featurePoint.properties[pointKeyName]
let keyConvertedFromMapping = mappingKeys[mappingKeys.indexOf(pointKeyName)]
let mappingConfigOfTag = this.mapping_config.tags[pointKeyName]
debugLog('========== mappingConfigOfTag', mappingConfigOfTag)
debugLog('convertProperty: found element', pointKeyName, '=>', keyConvertedFromMapping, 'value : ', valueConvertedFromMapping)
let convertedValue = originalValue
let typeOfConfigForKey = typeof mappingConfigOfTag
let isStringValue = typeOfConfigForKey === 'string'
let isConfigMappingObject = typeOfConfigForKey === 'object'
debugLog('convertProperty: - typeofValue', typeOfConfigForKey)
debugLog('convertProperty: - pointKeyName', pointKeyName)
debugLog('convertProperty: - valueConvertedFromMapping', valueConvertedFromMapping)
debugLog('typeof valueConvertedFromMapping === \'string\'', typeOfConfigForKey)
debugLog('convertProperty: isStringValue?', valueConvertedFromMapping, isStringValue)
debugLog('convertProperty: isStringValue?', valueConvertedFromMapping, isStringValue)
debugLog('mappingConfigOfTag', mappingConfigOfTag)
debugLog('typeOfConfigForKey', typeOfConfigForKey)
/**
* conversion si la clé à une config d'une string, on ne change que la clé, pas la valeur
*/
if (isStringValue) {
debugLog('convertProperty: -- string value')
debugLog('convertProperty: -- string value')
debugLog('convertProperty: -- simple conversion : ', pointKeyName, '=> ', mappingConfigOfTag, '_', originalValue, '=>', valueConvertedFromMapping)
debugLog('convertProperty: -- convertedValue', convertedValue)
convertedValue = valueConvertedFromMapping
if (convertedValue) {
newProperties[mappingConfigOfTag] = convertedValue
}
} else {
debugLog('convertProperty: no string value')
}
if (isConfigMappingObject) {
let configObject = mappingConfigOfTag
debugLog('convertProperty: is config object', configObject)
let newKey: any = '' + pointKeyName
let remove_original_key = false;
if (configObject.key_converted) {
newKey = configObject.key_converted
}
if (configObject.truthy_value) {
// convertir la valeur, si elle est truthy, la transformer en ce que donne la propriété truthy_value
// exemple: le jeu de données dit que la colonne cable_t2_attache vaut "True", mais on veut le convertir en "1".
// on met donc truthy_value: '1'
debugLog('truthy_value', originalValue)
if (this.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = configObject.truthy_value
}
}
if (configObject.falsy_value) {
if (this.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = configObject.falsy_value
}
}
/**
* conversion booléenne
*/
if (mappingValueObject.convert_to_boolean_value) {
debugLog('convertProperty: is boolean_value_conversion')
debugLog('convertProperty: ==========> original value', originalValue)
if (this.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = 'yes'
}
if (this.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = 'no'
}
} else {
debugLog('convertProperty: is NOT having boolean_value_conversion', mappingValueObject)
}
if (configObject.remove_original_key) {
remove_original_key = true
}
if (configObject.ignore_if_falsy && this.falsyValues.indexOf(originalValue) !== -1) {
remove_original_key = true
}
/**
* config pour une clé
* nous pouvons renseigner une string ou un objet décrivant les transformations à réaliser
*/
if (!remove_original_key && configObject.conditional_values) {
debugLog('convertProperty: conditional_values__________',
configObject.conditional_values)
let keysConditionnalValues: any = Object.keys(configObject.conditional_values)
let isFoundValue = keysConditionnalValues.indexOf(originalValue)
debugLog('isFoundValue', isFoundValue, originalValue)
debugLog('keysConditionnalValues', keysConditionnalValues)
if (isFoundValue > -1) {
let conditionnalConfig: any = configObject.conditional_values[keysConditionnalValues[isFoundValue]]
/** ----------------------
* gestion des valeurs conditionnelles
* ---------------------- */
debugLog('conditionnalConfig', conditionnalConfig)
if (conditionnalConfig.ignore_this_data) {
debugLog(`on ignore cette clé car sa valeur "${originalValue}" est à exclure: `, pointKeyName, '=>', newKey)
remove_original_key = true;
}
if (conditionnalConfig.tags_to_add) {
// on peut définir un ensemble de tags à rajouter
let tagKeys = Object.keys(conditionnalConfig.tags_to_add)
debugLog('conditionnalConfig.tags_to_add', conditionnalConfig.tags_to_add)
conditionnalConfig.tags_to_add.forEach((object: any, pair: any) => {
debugLog('object', object)
debugLog('pair', pair)
let key: any = Object.keys(object)
key = key[0]
let value = object[key]
debugLog('key', key)
debugLog('value', value)
newProperties[key] = value
})
}
if (conditionnalConfig.truthy_value) {
// convertir la valeur, si elle est truthy, la transformer en ce que donne la propriété truthy_value
// exemple: le jeu de données dit que la colonne cable_t2_attache vaut "True", mais on veut le convertir en "1".
// on met donc truthy_value: '1'
if (this.truthyValues.indexOf(originalValue) !== -1) {
convertedValue = conditionnalConfig.truthy_value
}
}
if (conditionnalConfig.falsy_value) {
if (this.falsyValues.indexOf(originalValue) !== -1) {
convertedValue = conditionnalConfig.falsy_value
}
}
if (conditionnalConfig.transform_function) {
// une transformation de la valeur
// apply transformation to value
convertedValue = conditionnalConfig.transform_function(originalValue)
}
// use the value converted
else if (conditionnalConfig.value_converted) {
convertedValue = conditionnalConfig.value_converted
}
}
}
debugLog('convertProperty: convertedValue ==========> {', newKey, ':', convertedValue, '}')
debugLog(' =============== remove_original_key',newKey, remove_original_key)
if (!remove_original_key && newKey && convertedValue && !configObject.ignore_this_data) {
debugLog('convertProperty: added')
newProperties[newKey] = convertedValue.trim()
}
}
}
}
}
}

View File

@ -0,0 +1,74 @@
interface GeoJsonGeometry {
type:string,
coordinates:Array<number>,
}
interface GeoJsonProperties {
[key:string]: any,
}
interface GeoJsonFeature {
type:string,
geometry:GeoJsonGeometry,
properties:GeoJsonProperties,
}
export interface FeatureCollection{
type:string,
features:Array<GeoJsonFeature>,
}
export interface BoundingBoxCoordinatesType{
xMin: number,
xMax: number,
yMin: number,
yMax: number,
}
export default interface MappingConfigType{
config_name: string,
config_author: string,
add_not_mapped_tags_too: boolean,
default_properties_of_point: object,
source: object,
filters: object,
tags: FeaturePropertyMappingConfigType
}
/**
* configuration concernant toutes les valeurs
*/
export interface FeaturePropertyMappingConfigType{
[key:string]: any,
convert_to_boolean_value?:boolean,
remove_original_key?:boolean,
conditionnal_values?:ConditionnalValuesType,
transform_function?:Function,
}
/**
* choix de conversion de la valeur originale selon des critères donnés
*/
export interface ConditionnalValuesConfigType{
key_converted?:string,
value_converted?:string,
truthy_value?:any,
falsy_value?:any, // si la valeur originale est falsy, la convertir en la valeur donnée ici
ignore_this_data?:boolean,
tags_to_add?:TagsToAddConfig,
transform_function?:Function,
}
export interface ConditionnalValuesType{
[key:string]: ConditionnalValuesConfigType,
}
interface OneOSMTag {
[key:string]: string,
}
export interface TagsToAddConfig{
tags_to_add: Array<OneOSMTag>
}

69
mappings/utils.ts Normal file
View File

@ -0,0 +1,69 @@
import fs from 'fs'
let show_debug = 0
// show_debug = 1
let output_folder = 'output';
// console.log('----------------------show_debug', show_debug)
/**
* wrapper de log qui se montre uniquemnt si show_debug a é activé
* @param args
*/
function debugLog(...args: any[]) {
if (show_debug) {
console.log('### debug: ', ...args)
}
}
let listOfBooleanKeys = [
"prise_type_ef",
"prise_type_2",
"prise_type_combo_ccs",
"prise_type_chademo",
"gratuit",
"paiement_acte",
"paiement_cb",
"cable_t2_attache"
]
/**
*
* @param pointKeyName
* @returns {boolean}
*/
function isBooleanKey(pointKeyName: string): boolean {
return listOfBooleanKeys.indexOf(pointKeyName) !== -1
}
/**
* crée un fichier dans le dossier par défaut, output
* @param fileName
* @param fileContent
*/
function writeFile(fileName: string, fileContent: any) {
debugLog('write file ', fileName)
return fs.writeFile(
`./${output_folder}/${fileName}`,
fileContent,
'utf8',
(err) => {
if (err) {
console.log(`Error writing file: ${err}`)
} else {
console.log(`File ${fileName} is written successfully!`)
}
}
)
}
export default {
debugLog,
isBooleanKey,
writeFile
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<osm version="0.6" generator="geojsontoosm"><node id="-1" lat="45.635079000000005" lon="4.822158999999999"><tag k="amenity" v="charging_station"/><tag k="operator" v="ELECTRA"/><tag k="owner:ref:FR:SIREN" v="891624884"/><tag k="email" v="help@electra.com"/><tag k="network" v="ELECTRA"/><tag k="socket:type2_combo" v="yes"/><tag k="fee" v="false"/><tag k="authentication:none" v="true"/><tag k="reservation" v="yes"/><tag k="opening_hours" v="24/7"/><tag k="start_date" v="2022-10-27"/></node></osm>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<osm version="0.6" generator="geojsontoosm"><node id="-1" lat="45.635079000000005" lon="4.822158999999999"><tag k="amenity" v="charging_station"/><tag k="operator" v="ELECTRA"/><tag k="owner:ref:FR:SIREN" v="891624884"/><tag k="email" v="help@electra.com"/><tag k="network" v="ELECTRA"/><tag k="socket:type2_combo" v="yes"/><tag k="fee" v="false"/><tag k="authentication:none" v="true"/><tag k="reservation" v="yes"/><tag k="opening_hours" v="24/7"/><tag k="start_date" v="2022-10-27"/></node></osm>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More