More improvements to the charging station theme

This commit is contained in:
Pieter Vander Vennet 2021-09-13 01:21:25 +02:00
parent bd37cc812f
commit 3492b5d403
4 changed files with 1611 additions and 98 deletions

File diff suppressed because it is too large Load diff

View file

@ -129,10 +129,12 @@
{
"#": "capacity",
"render": {
"en": "{capacity} vehicles can be charged here at the same time"
"en": "{capacity} vehicles can be charged here at the same time",
"nl": "{capacity} voertuigen kunnen hier op hetzelfde moment opgeladen worden"
},
"question": {
"en": "How much vehicles can be charged here at the same time?"
"en": "How much vehicles can be charged here at the same time?",
"nl": "Hoeveel voertuigen kunnen hier opgeladen worden?"
},
"freeform": {
"key": "capacity",
@ -277,6 +279,58 @@
}
]
},
{
"#": "fee/charge",
"question": {
"en": "How much does one have to pay to use this charging station?",
"nl": "Hoeveel kost het gebruik van dit oplaadpunt?"
},
"freeform": {
"key": "charge",
"addExtraTags": [
"fee=yes"
]
},
"render": {
"en": "Using this charging station costs <b>{charge}</b>",
"nl": "Dit oplaadpunt gebruiken kost <b>{charge}</b>"
},
"mappings": [
{
"if": {
"and": [
"fee=no",
"charge="
]
},
"then": {
"nl": "Gratis te gebruiken",
"en": "Free to use"
}
}
]
},
{
"builtin": "payment-options",
"override": {
"condition": {
"or": [
"fee=yes",
"charge~*"
]
},
"mappings+": [
{
"if": "payment:app=yes",
"ifnot": "payment:app=no",
"then": {
"en": "Payment is done using a dedicated app",
"nl": "Betalen via een app van het netwerk"
}
}
]
}
},
{
"#": "Network",
"render": {
@ -518,6 +572,9 @@
],
"title": {
"en": "Charging station"
},
"preciseInput": {
"preferredBackground": "map"
}
}
],

View file

@ -1,34 +1,80 @@
import {readFileSync, writeFileSync} from "fs";
import {Utils} from "../../../Utils";
import {TagRenderingConfigJson} from "../../../Models/ThemeConfig/Json/TagRenderingConfigJson";
import ScriptUtils from "../../../scripts/ScriptUtils";
function colonSplit(value: string): string[] {
return value.split(";").map(v => v.replace(/"/g, '').trim().toLowerCase()).filter(s => s !== "");
}
function loadCsv(file): {
key: string,
image: string,
description: Map<string, string>,
countryWhiteList?: string[],
commonVoltages?: number[],
commonCurrents?: number[],
commonOutputs?: string[]
}[] {
const entries: string[] = Utils.NoNull(readFileSync(file, "utf8").split("\n").map(str => str.trim()))
const header = entries.shift().split(",")
return Utils.NoNull(entries.map(entry => {
const values = entry.split(",").map(str => str.trim())
if (values[0] === undefined || values[0] === "") {
return undefined;
}
const v = {}
const colonSeperated = ["commonVoltages", "commonOutputs", "commonCurrents", "countryWhiteList"]
const descriptionTranslations = new Map<string, string>()
for (let j = 0; j < header.length; j++) {
const key = header[j];
if (key.startsWith("description")) {
const language = key.substring("description:".length)
descriptionTranslations.set(language, values[j])
}
if (colonSeperated.indexOf(key) >= 0) {
v[key] = colonSplit(values[j])
} else {
v[key] = values[j]
}
}
v["description"] = descriptionTranslations
return <any>v;
}))
}
// SMall script to output the properties of the types.csv as json to add in the tagRenderingGroup. Should be copied manually
function run(file, protojson) {
const entries: string[] = Utils.NoNull(readFileSync(file, "utf8").split("\n").map(str => str.trim()))
entries.shift()
const overview_question_answers = []
const questions = []
const filterOptions: { question: string, osmTags?: string } [] = [
const questions: TagRenderingConfigJson[] = []
const filterOptions: { question: any, osmTags?: string } [] = [
{
question: "All connectors"
question: {
en: "All connectors",
nl: "Alle types"
}
}
]
for (const entry of entries) {
const [key, image, description, whitelist] = entry.split(",").map(str => str.trim())
if (key === "") {
continue;
const entries = loadCsv(file)
for (const e of entries) {
const txt = {
en: `<img style='width:3rem; margin-left: 1rem; margin-right: 1rem' src='./assets/layers/charging_station/${e.image}'/> ${e.description.get("en")}`,
nl: `<img style='width:3rem; margin-left: 1rem; margin-right: 1rem' src='./assets/layers/charging_station/${e.image}'/> ${e.description.get("nl")}`
}
const txt = `<img style='width:3rem; margin-left: 1rem; margin-right: 1rem' src='./assets/layers/charging_station/${image}'/> ${description}`
const json = {
if: `${key}=1`,
ifnot: `${key}=`,
if: `${e.key}=1`,
ifnot: `${e.key}=`,
then: txt,
}
if (whitelist) {
const countries = whitelist.replace(/"/g, '').split(",").map(country => "_country!=" + country) //HideInAnswer if it is in the wrong country
if (e.countryWhiteList !== undefined && e.countryWhiteList.length > 0) {
const countries = e.countryWhiteList.map(country => "_country!=" + country) //HideInAnswer if it is in the wrong country
json["hideInAnswer"] = {or: countries}
}
@ -37,32 +83,123 @@ function run(file, protojson) {
// We add a second time for any amount to trigger a visualisation; but this is not an answer option
const no_ask_json = {
if: {
and: [`${key}~*`, `${key}!=1`]
and: [`${e.key}~*`, `${e.key}!=1`]
},
then: txt,
hideInAnswer: true
}
overview_question_answers.push(no_ask_json)
const indivQ = {
const descrWithImage_en = `<b>${e.description.get("en")}</b> <img style='width:1rem;' src='./assets/layers/charging_station/${e.image}'/>`
const descrWithImage_nl = `<b>${e.description.get("nl")}</b> <img style='width:1rem;' src='./assets/layers/charging_station/${e.image}'/>`
questions.push({
question: {
en: `How much plugs of type ${description} <img style='width:1rem; margin-left: 1rem; margin-right: 1rem' src='./assets/layers/charging_station/${image}'/> are available here?`
en: `How much plugs of type ${descrWithImage_en} are available here?`,
nl: `Hoeveel stekkers van type ${descrWithImage_nl} heeft dit oplaadpunt?`,
},
render: {
en: `There are ${descrWithImage_en} plugs of type ${e.description.get("en")} available here`,
nl: `Hier zijn ${descrWithImage_nl} stekkers van het type ${e.description.get("nl")}`
},
render: `There are <b>{${key}}</b> <img style='width:1rem' src='./assets/layers/charging_station/${image}'/> plugs of type ${description} available here`,
freeform: {
key: key,
key: e.key,
type: "pnat"
},
condition: `${key}~*`
condition: {
and: [`${e.key}~*`, `${e.key}!=0`]
}
})
}
questions.push({
question: {
en: `What voltage do the plugs with ${descrWithImage_en} offer?`,
nl: `Welke spanning levert de stekker van type ${descrWithImage_nl}`
},
render: {
en: `${descrWithImage_en} outputs {${e.key}:voltage} volt`,
nl: `${descrWithImage_nl} heeft een spanning van {${e.key}:voltage} volt`
},
freeform: {
key: `${e.key}:voltage`,
type: "pfloat"
},
mappings: e.commonVoltages.map(voltage => {
return {
if: `socket:${e.key}:voltage=${voltage} V`,
then: {
en: `${descrWithImage_en} outputs ${voltage} volt`,
nl: `${descrWithImage_nl} heeft een spanning van ${voltage} volt`
}
}
}),
condition: {
and: [`${e.key}~*`, `${e.key}!=0`]
}
})
questions.push(indivQ)
questions.push({
question: {
en: `What current do the plugs with ${descrWithImage_en} offer?`,
nl: `Welke stroom levert de stekker van type ${descrWithImage_nl}?`,
},
render: {
en: `${descrWithImage_en} outputs at most {${e.key}:current}A`,
nl: `${descrWithImage_nl} levert een stroom van maximaal {${e.key}:current}A`
},
freeform: {
key: `${e.key}:current`,
type: "pfloat"
},
mappings: e.commonCurrents.map(current => {
return {
if: `socket:${e.key}:current=${current} A`,
then: {
en: `${descrWithImage_en} outputs at most ${current} A`,
nl: `${descrWithImage_nl} levert een stroom van maximaal ${current} A`
}
}
}),
condition: {
and: [`${e.key}~*`, `${e.key}!=0`]
}
})
questions.push({
question: {
en: `What power output does a single plug of type ${descrWithImage_en} offer?`,
nl: `Welk vermogen levert een enkele stekker van type ${descrWithImage_nl}?`,
},
render: {
en: `${descrWithImage_en} outputs at most {${e.key}:output}`,
nl: `${descrWithImage_nl} levert een vermogen van maximaal {${e.key}:output}`
},
freeform: {
key: `${e.key}:output`,
type: "pfloat"
},
mappings: e.commonOutputs.map(output => {
return {
if: `socket:${e.key}:output=${output}`,
then: {
en: `${descrWithImage_en} outputs at most ${output}`,
nl: `${descrWithImage_nl} levert een vermogen van maximaal ${output}`
}
}
}),
condition: {
and: [`${e.key}~*`, `${e.key}!=0`]
}
})
filterOptions.push({
question: `Has a ${description} <img style='width:1rem' src='./assets/layers/charging_station/${image}'/> connector`,
osmTags: `${key}~*`
question: {
en: `Has a ${descrWithImage_en} connector`,
nl: `Heeft een ${descrWithImage_nl}`
},
osmTags: `${e.key}~*`
})
}
@ -82,11 +219,99 @@ function run(file, protojson) {
proto["filter"].push({
options: filterOptions
})
proto["units"] = [
{
appliesToKey: entries.map(e => e.key + ":voltage"),
applicableUnits: [{
canonicalDenomination: 'V',
alternativeDenomination: ["v", "volt", "voltage",'V','Volt'],
human: {
en: "Volts",
nl: "volt"
}
}],
eraseInvalidValues: true
},
{
appliesToKey: entries.map(e => e.key + ":current"),
applicableUnits: [{
canonicalDenomination: 'A',
alternativeDenomination: ["a", "amp", "amperage",'A'],
human: {
en: "A",
nl: "A"
}
}],
eraseInvalidValues: true
},
{
appliesToKey: entries.map(e => e.key + ":output"),
applicableUnits: [{
canonicalDenomination: 'kW',
alternativeDenomination: ["kilowatt"],
human: {
en: "kilowatt",
nl: "kilowatt"
}
},
{
canonicalDenomination: 'mW',
alternativeDenomination: ["megawatt"],
human: {
en: "megawatt",
nl: "megawatt"
}
}],
eraseInvalidValues: true
},
];
writeFileSync("charging_station.json", JSON.stringify(proto, undefined, " "))
}
async function queryTagInfo(file, type, clean: ((s: string) => string)) {
for (const e of loadCsv(file)) {
const value = await ScriptUtils.TagInfoHistogram(e.key + ":" + type)
const result = value.data
const counts = new Map<string, number>()
// console.log(result)
for (const r of result) {
let key = r.value;
key = clean(key)
key.trim();
if (key.indexOf('-') >= 0) {
continue
}
if (r.fraction < 0.05) {
continue
}
if (counts.has(key)) {
counts.set(key, counts.get(key) + r.count)
} else {
counts.set(key, r.count)
}
}
const countsArray = Array.from(counts.keys())
countsArray.sort()
// console.log(`${e.key}:${type} = ${countsArray.join(";")}`)
console.log(`${countsArray.join(";")}`)
}
}
try {
run("types.csv", "charging_station.protojson")
// queryTagInfo("types.csv","voltage", true)
// queryTagInfo("types.csv", "current", true)
/* queryTagInfo("types.csv", "output", s => {
if(s.endsWith("kW")){
s = s.substring(0, s.length - 2)
}
s = s.trim()
return s + " kW"
})*/
} catch (e) {
console.error(e)
}

View file

@ -1,10 +1,10 @@
Key in OSM,image,Description,Country-whitelist,,,,,,,
socket:schuko,CEE7_4F.svg,<b>Schuko wall plug</b> without ground pin (CEE7/4 type F),"be,fr,ma,tn,pl,cs,sk,mo"
socket:typee,TypeE.svg,<b>European wall plug</b> with ground pin (CEE7/4 type E),,,,,,,,
socket:chademo,Chademo_type4.svg,<b>Chademo</b>,,,,,,,,
socket:type1_cable,Type1_J1772.svg,<b>Type 1 with cable</b> (J1772),,,,,,,,
socket:type1,Type1_J1772.svg,<b>Type 1 <i>without</i> cable</b> (J1772),,,,,,,,
socket:type1_combo,Type1-ccs.svg,<b>Type 1 CCS</b> (aka Type 1 Combo),,,,,,,,
socket:tesla_supercharger,Tesla-hpwc-model-s.svg,<b>Tesla Supercharger</b>,,,,,,,,
socket:type2,Type2_socket.svg,<b>Type 2</b> (mennekes),,,,,,,,
socket:type2_combo,Type2_CCS.svg,<b>Type 2 CCS</b> (mennekes),,,,,,,,
key,image,description:en,countryWhitelist,commonVoltages,commonCurrents,commonOutputs,description:nl
socket:schuko,CEE7_4F.svg,<b>Schuko wall plug</b> without ground pin (CEE7/4 type F),be;fr;ma;tn;pl;cs;sk;mo,230,16,3.6 kW,<b>Schuko stekker</b> zonder aardingspin (CEE7/4 type F)
socket:typee,TypeE.svg,<b>European wall plug</b> with ground pin (CEE7/4 type E),,230,16,3 kW;22 kW;,<b>Europese stekker</b> met aardingspin (CEE7/4 type E)
socket:chademo,Chademo_type4.svg,<b>Chademo</b>,,500,120,50 kW,
socket:type1_cable,Type1_J1772.svg,<b>Type 1 with cable</b> (J1772),,200;240,32,3.7 kW;7 kW,<b>Type 1 met kabel</b> (J1772)
socket:type1,Type1_J1772.svg,<b>Type 1 <i>without</i> cable</b> (J1772),,200;240,32,3.7 kW;6.6 kW;7 kW;7.2 kW,<b>Type 1 <i>zonder</i> kabel</b> (J1772)
socket:type1_combo,Type1-ccs.svg,<b>Type 1 CCS</b> (aka Type 1 Combo),,400;1000,50;125,50 kW;62.5 kW;150 kW;350 kW;,
socket:tesla_supercharger,Tesla-hpwc-model-s.svg,<b>Tesla Supercharger</b>,,480,125;350,120 kW;150 kW;250 kW,
socket:type2,Type2_socket.svg,<b>Type 2</b> (mennekes),,230;400,16;32,11 kW;22 kW,
socket:type2_combo,Type2_CCS.svg,<b>Type 2 CCS</b> (mennekes),,500;920,125;350,50 kW,

Can't render this file because it has a wrong number of fields in line 2.