From 073bd0984b486270c4537353b7e96b7111adcbb3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 11 Mar 2022 18:55:04 +0100 Subject: [PATCH] Add persistent OCPP parameters key/value support by CS generated name MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Issue #196 Signed-off-by: Jérôme Benoit --- .eslintrc | 11 +++ package.json | 2 +- rollup.config.js | 2 +- .../evlink.station-template.json | 2 + .../schneider-imredd.station-template.json | 2 + .../schneider.station-template.json | 2 + src/charging-station/ChargingStation.ts | 72 +++++++++++++++++-- 7 files changed, 86 insertions(+), 7 deletions(-) diff --git a/.eslintrc b/.eslintrc index 8b1a3783..0c4343ab 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,14 @@ { "root": true, + "env": { + "es2020": true, + "node": true, + "mocha": true +}, + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, "extends": [ "eslint:recommended", "plugin:import/errors", @@ -114,6 +123,8 @@ "files": ["**/*.ts"], "parser": "@typescript-eslint/parser", "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module", "project": "./tsconfig.json" }, "extends": [ diff --git a/package.json b/package.json index 806ff59e..d48b2958 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "main": "./dist/start.js", "lint-staged": { - "*.{js,ts}": [ + "src/**/*.{js,ts}": [ "prettier --write", "eslint --cache --fix" ] diff --git a/rollup.config.js b/rollup.config.js index b1114284..e086e909 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -49,7 +49,7 @@ export default { }), isDevelopmentBuild && istanbul(), del({ - targets: 'dist/*', + targets: ['dist/*', '!dist/assets', 'dist/assets/*.json', 'dist/assets/station-templates'], }), copy({ targets: [{ src: 'src/assets', dest: 'dist/' }], diff --git a/src/assets/station-templates/evlink.station-template.json b/src/assets/station-templates/evlink.station-template.json index 0b8e1506..c78befd2 100644 --- a/src/assets/station-templates/evlink.station-template.json +++ b/src/assets/station-templates/evlink.station-template.json @@ -1,4 +1,6 @@ { + "supervisionUrlOcppConfiguration": true, + "supervisionUrlOcppKey": "ocppcentraladdress", "authorizationFile": "authorization-tags.json", "baseName": "CS-EVLINK", "chargePointModel": "MONOBLOCK", diff --git a/src/assets/station-templates/schneider-imredd.station-template.json b/src/assets/station-templates/schneider-imredd.station-template.json index 4609eac2..ac02a575 100644 --- a/src/assets/station-templates/schneider-imredd.station-template.json +++ b/src/assets/station-templates/schneider-imredd.station-template.json @@ -1,4 +1,6 @@ { + "supervisionUrlOcppConfiguration": true, + "supervisionUrlOcppKey": "ocppcentraladdress", "authorizationFile": "authorization-tags.json", "baseName": "CS-SCHNEIDER", "chargePointModel": "MONOBLOCK", diff --git a/src/assets/station-templates/schneider.station-template.json b/src/assets/station-templates/schneider.station-template.json index 605a7fe1..1968f40e 100644 --- a/src/assets/station-templates/schneider.station-template.json +++ b/src/assets/station-templates/schneider.station-template.json @@ -1,4 +1,6 @@ { + "supervisionUrlOcppConfiguration": true, + "supervisionUrlOcppKey": "ocppcentraladdress", "authorizationFile": "authorization-tags.json", "baseName": "CS-SCHNEIDER", "chargePointModel": "MONOBLOCK", diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index a451c5ee..6371501a 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -74,6 +74,7 @@ export default class ChargingStation { public heartbeatSetInterval!: NodeJS.Timeout; public ocppRequestService!: OCPPRequestService; private readonly index: number; + private configurationFile!: string; private bootNotificationRequest!: BootNotificationRequest; private bootNotificationResponse!: BootNotificationResponse | null; private connectorsConfigurationHash!: string; @@ -594,6 +595,7 @@ export default class ChargingStation { if (keyFound) { const keyIndex = this.configuration.configurationKey.indexOf(keyFound); this.configuration.configurationKey[keyIndex].value = value; + this.saveConfiguration(); } else { logger.error( `${this.logPrefix()} Trying to set a value on a non existing configuration key: %j`, @@ -734,7 +736,13 @@ export default class ChargingStation { private initialize(): void { this.stationInfo = this.buildStationInfo(); - this.configuration = this.getTemplateChargingStationConfiguration(); + this.configurationFile = path.join( + path.resolve(__dirname, '../'), + 'assets', + 'configurations', + this.stationInfo.chargingStationId + '.json' + ); + this.configuration = this.getConfiguration(); delete this.stationInfo.Configuration; this.bootNotificationRequest = { chargePointModel: this.stationInfo.chargePointModel, @@ -940,6 +948,64 @@ export default class ChargingStation { Constants.DEFAULT_CONNECTION_TIMEOUT.toString() ); } + this.saveConfiguration(); + } + + private getConfigurationFromTemplate(): ChargingStationConfiguration { + return this.stationInfo.Configuration ?? ({} as ChargingStationConfiguration); + } + + private getConfigurationFromFile(): ChargingStationConfiguration | null { + let configuration: ChargingStationConfiguration = null; + if (this.configurationFile && fs.existsSync(this.configurationFile)) { + try { + const fileDescriptor = fs.openSync(this.configurationFile, 'r'); + configuration = JSON.parse( + fs.readFileSync(fileDescriptor, 'utf8') + ) as ChargingStationConfiguration; + fs.closeSync(fileDescriptor); + } catch (error) { + FileUtils.handleFileException( + this.logPrefix(), + 'Configuration', + this.configurationFile, + error as NodeJS.ErrnoException + ); + } + } + return configuration; + } + + private saveConfiguration(): void { + if (this.configurationFile) { + try { + if (!fs.existsSync(path.dirname(this.configurationFile))) { + fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true }); + } + const fileDescriptor = fs.openSync(this.configurationFile, 'w'); + fs.writeFileSync(fileDescriptor, JSON.stringify(this.configuration, null, 2)); + fs.closeSync(fileDescriptor); + } catch (error) { + FileUtils.handleFileException( + this.logPrefix(), + 'Configuration', + this.configurationFile, + error as NodeJS.ErrnoException + ); + } + } else { + logger.error( + `${this.logPrefix()} Trying to save charging station configuration to undefined file` + ); + } + } + + private getConfiguration(): ChargingStationConfiguration { + let configuration: ChargingStationConfiguration = this.getConfigurationFromFile(); + if (!configuration) { + configuration = this.getConfigurationFromTemplate(); + } + return configuration; } private async onOpen(): Promise { @@ -1141,10 +1207,6 @@ export default class ChargingStation { logger.error(this.logPrefix() + ' WebSocket error: %j', error); } - private getTemplateChargingStationConfiguration(): ChargingStationConfiguration { - return this.stationInfo.Configuration ?? ({} as ChargingStationConfiguration); - } - private getAuthorizationFile(): string | undefined { return ( this.stationInfo.authorizationFile && -- 2.34.1