Add persistent OCPP parameters key/value support by CS generated name
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 11 Mar 2022 17:55:04 +0000 (18:55 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 11 Mar 2022 17:55:04 +0000 (18:55 +0100)
Issue #196

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
.eslintrc
package.json
rollup.config.js
src/assets/station-templates/evlink.station-template.json
src/assets/station-templates/schneider-imredd.station-template.json
src/assets/station-templates/schneider.station-template.json
src/charging-station/ChargingStation.ts

index 8b1a37836329e0dd6dbb63b11ed9598ffdfcdae4..0c4343ab5e2877a877acee92f3185e3a424ae7b0 100644 (file)
--- 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",
       "files": ["**/*.ts"],
       "parser": "@typescript-eslint/parser",
       "parserOptions": {
+        "ecmaVersion": 2020,
+        "sourceType": "module",
         "project": "./tsconfig.json"
       },
       "extends": [
index 806ff59e248fd1fc2a3c9435259b3cc71a879093..d48b2958f972ef3a2f2e270272422317a0ad9c17 100644 (file)
@@ -27,7 +27,7 @@
   ],
   "main": "./dist/start.js",
   "lint-staged": {
-    "*.{js,ts}": [
+    "src/**/*.{js,ts}": [
       "prettier --write",
       "eslint --cache --fix"
     ]
index b1114284ea7bbe9d5d596fd46d04ce11f3a8a2e4..e086e90909abc0385768a0ba84ed847edf964e0b 100644 (file)
@@ -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/' }],
index 0b8e1506e081a6f3f2ddcc1ac09c4cf07cb3f725..c78befd2dd6377a2065e767e0d7e6950dc79983c 100644 (file)
@@ -1,4 +1,6 @@
 {
+  "supervisionUrlOcppConfiguration": true,
+  "supervisionUrlOcppKey": "ocppcentraladdress",
   "authorizationFile": "authorization-tags.json",
   "baseName": "CS-EVLINK",
   "chargePointModel": "MONOBLOCK",
index 4609eac287cf244c1378b7f23ffd9ba88a1d27e8..ac02a5753b4abbdc86f44c8f13829219f7c2bea6 100644 (file)
@@ -1,4 +1,6 @@
 {
+  "supervisionUrlOcppConfiguration": true,
+  "supervisionUrlOcppKey": "ocppcentraladdress",
   "authorizationFile": "authorization-tags.json",
   "baseName": "CS-SCHNEIDER",
   "chargePointModel": "MONOBLOCK",
index 605a7fe102f66392153260337f6930c143ab101e..1968f40e74c0b4f297dabafb4d5b1b92ebec20ba 100644 (file)
@@ -1,4 +1,6 @@
 {
+  "supervisionUrlOcppConfiguration": true,
+  "supervisionUrlOcppKey": "ocppcentraladdress",
   "authorizationFile": "authorization-tags.json",
   "baseName": "CS-SCHNEIDER",
   "chargePointModel": "MONOBLOCK",
index a451c5ee4668b31cbad728fa4881cf2356a812a8..6371501a838b375031f284a81358e1e232a2dba3 100644 (file)
@@ -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<void> {
@@ -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 &&