Keep track of the connector status and restore it properly on reload.
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 10 Nov 2020 19:19:40 +0000 (20:19 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 10 Nov 2020 19:19:40 +0000 (20:19 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
package-lock.json
package.json
src/charging-station/ChargingStation.ts
src/types/ChargePointStatus.ts [new file with mode: 0644]
src/types/MeasurandValues.ts

index e4c939cf1772ea25a14894f40cd59bf5126cb68e..58ee363bfde1f462d26678633c1ff5bf41e1505c 100644 (file)
       "dev": true
     },
     "@types/node": {
-      "version": "14.14.6",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz",
-      "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==",
+      "version": "14.14.7",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz",
+      "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==",
       "dev": true
     },
     "@types/offscreencanvas": {
       }
     },
     "@types/ws": {
-      "version": "7.2.9",
-      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.9.tgz",
-      "integrity": "sha512-gmXYAXr7G4BrRMnkGQGkGonc3ArVro9VZd//C1uns/qqsJyl2dxaJdlPMhZbcq5MTxFFC+ttFWtHSfVW5+hlRA==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz",
+      "integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==",
       "dev": true,
       "requires": {
         "@types/node": "*"
       }
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.6.1.tgz",
-      "integrity": "sha512-SNZyflefTMK2JyrPfFFzzoy2asLmZvZJ6+/L5cIqg4HfKGiW2Gr1Go1OyEVqne/U4QwmoasuMwppoBHWBWF2nA==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.7.0.tgz",
+      "integrity": "sha512-li9aiSVBBd7kU5VlQlT1AqP0uWGDK6JYKUQ9cVDnOg34VNnd9t4jr0Yqc/bKxJr/tDCPDaB4KzoSFN9fgVxe/Q==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "4.6.1",
-        "@typescript-eslint/scope-manager": "4.6.1",
+        "@typescript-eslint/experimental-utils": "4.7.0",
+        "@typescript-eslint/scope-manager": "4.7.0",
         "debug": "^4.1.1",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^3.0.0",
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.1.tgz",
-      "integrity": "sha512-qyPqCFWlHZXkEBoV56UxHSoXW2qnTr4JrWVXOh3soBP3q0o7p4pUEMfInDwIa0dB/ypdtm7gLOS0hg0a73ijfg==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.7.0.tgz",
+      "integrity": "sha512-cymzovXAiD4EF+YoHAB5Oh02MpnXjvyaOb+v+BdpY7lsJXZQN34oIETeUwVT2XfV9rSNpXaIcknDLfupO/tUoA==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.3",
-        "@typescript-eslint/scope-manager": "4.6.1",
-        "@typescript-eslint/types": "4.6.1",
-        "@typescript-eslint/typescript-estree": "4.6.1",
+        "@typescript-eslint/scope-manager": "4.7.0",
+        "@typescript-eslint/types": "4.7.0",
+        "@typescript-eslint/typescript-estree": "4.7.0",
         "eslint-scope": "^5.0.0",
         "eslint-utils": "^2.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.6.1.tgz",
-      "integrity": "sha512-lScKRPt1wM9UwyKkGKyQDqf0bh6jm8DQ5iN37urRIXDm16GEv+HGEmum2Fc423xlk5NUOkOpfTnKZc/tqKZkDQ==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.7.0.tgz",
+      "integrity": "sha512-+meGV8bMP1sJHBI2AFq1GeTwofcGiur8LoIr6v+rEmD9knyCqDlrQcFHR0KDDfldHIFDU/enZ53fla6ReF4wRw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "4.6.1",
-        "@typescript-eslint/types": "4.6.1",
-        "@typescript-eslint/typescript-estree": "4.6.1",
+        "@typescript-eslint/scope-manager": "4.7.0",
+        "@typescript-eslint/types": "4.7.0",
+        "@typescript-eslint/typescript-estree": "4.7.0",
         "debug": "^4.1.1"
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.6.1.tgz",
-      "integrity": "sha512-f95+80r6VdINYscJY1KDUEDcxZ3prAWHulL4qRDfNVD0I5QAVSGqFkwHERDoLYJJWmEAkUMdQVvx7/c2Hp+Bjg==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.7.0.tgz",
+      "integrity": "sha512-ILITvqwDJYbcDCROj6+Ob0oCKNg3SH46iWcNcTIT9B5aiVssoTYkhKjxOMNzR1F7WSJkik4zmuqve5MdnA0DyA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.6.1",
-        "@typescript-eslint/visitor-keys": "4.6.1"
+        "@typescript-eslint/types": "4.7.0",
+        "@typescript-eslint/visitor-keys": "4.7.0"
       }
     },
     "@typescript-eslint/types": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.6.1.tgz",
-      "integrity": "sha512-k2ZCHhJ96YZyPIsykickez+OMHkz06xppVLfJ+DY90i532/Cx2Z+HiRMH8YZQo7a4zVd/TwNBuRCdXlGK4yo8w==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.7.0.tgz",
+      "integrity": "sha512-uLszFe0wExJc+I7q0Z/+BnP7wao/kzX0hB5vJn4LIgrfrMLgnB2UXoReV19lkJQS1a1mHWGGODSxnBx6JQC3Sg==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.1.tgz",
-      "integrity": "sha512-/J/kxiyjQQKqEr5kuKLNQ1Finpfb8gf/NpbwqFFYEBjxOsZ621r9AqwS9UDRA1Rrr/eneX/YsbPAIhU2rFLjXQ==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.7.0.tgz",
+      "integrity": "sha512-5XZRQznD1MfUmxu1t8/j2Af4OxbA7EFU2rbo0No7meb46eHgGkSieFdfV6omiC/DGIBhH9H9gXn7okBbVOm8jw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.6.1",
-        "@typescript-eslint/visitor-keys": "4.6.1",
+        "@typescript-eslint/types": "4.7.0",
+        "@typescript-eslint/visitor-keys": "4.7.0",
         "debug": "^4.1.1",
         "globby": "^11.0.1",
         "is-glob": "^4.0.1",
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.1.tgz",
-      "integrity": "sha512-owABze4toX7QXwOLT3/D5a8NecZEjEWU1srqxENTfqsY3bwVnl3YYbOh6s1rp2wQKO9RTHFGjKes08FgE7SVMw==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.7.0.tgz",
+      "integrity": "sha512-aDJDWuCRsf1lXOtignlfiPODkzSxxop7D0rZ91L6ZuMlcMCSh0YyK+gAfo5zN/ih6WxMwhoXgJWC3cWQdaKC+A==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.6.1",
+        "@typescript-eslint/types": "4.7.0",
         "eslint-visitor-keys": "^2.0.0"
       },
       "dependencies": {
index 89c42699218688402cc17cee1433100754005cd8..b3dde3660ec7d00b2704fd01cf8fe4c014fa4eec 100644 (file)
     "utf-8-validate": "^5.0.3"
   },
   "devDependencies": {
-    "@types/node": "^14.14.6",
+    "@types/node": "^14.14.7",
     "@types/uuid": "^8.3.0",
     "@types/worker-threads-pool": "^2.0.0",
-    "@types/ws": "^7.2.9",
-    "@typescript-eslint/eslint-plugin": "^4.6.1",
-    "@typescript-eslint/parser": "^4.6.1",
+    "@types/ws": "^7.4.0",
+    "@typescript-eslint/eslint-plugin": "^4.7.0",
+    "@typescript-eslint/parser": "^4.7.0",
     "clinic": "^7.0.0",
     "cross-env": "^7.0.2",
     "eslint": "^7.13.0",
index 44f1c9c55d48d0e3a520567946edf24229201a10..0e96596b91c1dcdd36af4d59402063b05e5d5044 100644 (file)
@@ -1,10 +1,11 @@
 import { PerformanceObserver, performance } from 'perf_hooks';
 
 import AutomaticTransactionGenerator from './AutomaticTransactionGenerator';
+import { ChargePointStatus } from '../types/ChargePointStatus';
 import Configuration from '../utils/Configuration';
 import Constants from '../utils/Constants.js';
 import ElectricUtils from '../utils/ElectricUtils';
-import { MeasurandValues } from '../types/MeasurandValues';
+import MeasurandValues from '../types/MeasurandValues';
 import OCPPError from './OcppError.js';
 import Statistics from '../utils/Statistics';
 import Utils from '../utils/Utils';
@@ -309,13 +310,15 @@ export default class ChargingStation {
     // Initialize connectors status
     for (const connector in this._connectors) {
       if (!this.getConnector(Utils.convertToInt(connector)).transactionStarted) {
-        if (this.getConnector(Utils.convertToInt(connector)).bootStatus) {
+        if (!this.getConnector(Utils.convertToInt(connector)).status && this.getConnector(Utils.convertToInt(connector)).bootStatus) {
           this.sendStatusNotification(Utils.convertToInt(connector), this.getConnector(Utils.convertToInt(connector)).bootStatus);
+        } else if (this.getConnector(Utils.convertToInt(connector)).status) {
+          this.sendStatusNotification(Utils.convertToInt(connector), this.getConnector(Utils.convertToInt(connector)).status);
         } else {
-          this.sendStatusNotification(Utils.convertToInt(connector), 'Available');
+          this.sendStatusNotification(Utils.convertToInt(connector), ChargePointStatus.AVAILABLE);
         }
       } else {
-        this.sendStatusNotification(Utils.convertToInt(connector), 'Charging');
+        this.sendStatusNotification(Utils.convertToInt(connector), ChargePointStatus.CHARGING);
       }
     }
     // Start the ATG
@@ -449,7 +452,7 @@ export default class ChargingStation {
     await this._stopMessageSequence();
     // eslint-disable-next-line guard-for-in
     for (const connector in this._connectors) {
-      await this.sendStatusNotification(Utils.convertToInt(connector), 'Unavailable');
+      await this.sendStatusNotification(Utils.convertToInt(connector), ChargePointStatus.UNAVAILABLE);
     }
     if (this._wsConnection && this._wsConnection.readyState === WebSocket.OPEN) {
       this._wsConnection.close();
@@ -480,7 +483,7 @@ export default class ChargingStation {
     }
   }
 
-  onOpen() {
+  onOpen(): void {
     logger.info(`${this._logPrefix()} Is connected to server through ${this._wsConnectionUrl}`);
     if (!this._isSocketRestart) {
       // Send BootNotification
@@ -500,7 +503,7 @@ export default class ChargingStation {
     this._isSocketRestart = false;
   }
 
-  onError(error) {
+  onError(error): void {
     switch (error) {
       case 'ECONNREFUSED':
         this._isSocketRestart = true;
@@ -512,7 +515,7 @@ export default class ChargingStation {
     }
   }
 
-  onClose(error) {
+  onClose(error): void {
     switch (error) {
       case 1000: // Normal close
       case 1005:
@@ -526,11 +529,11 @@ export default class ChargingStation {
     }
   }
 
-  onPing() {
+  onPing(): void {
     logger.debug(this._logPrefix() + ' Has received a WS ping (rfc6455) from the server');
   }
 
-  async onMessage(message) {
+  async onMessage(message) : Promise<void> {
     let [messageType, messageId, commandName, commandPayload, errorDetails] = [0, '', Constants.ENTITY_CHARGING_STATION, '', ''];
     try {
       // Parse the message
@@ -594,7 +597,7 @@ export default class ChargingStation {
     }
   }
 
-  async sendHeartbeat() {
+  async sendHeartbeat(): Promise<void> {
     try {
       const payload = {
         currentTime: new Date().toISOString(),
@@ -606,7 +609,7 @@ export default class ChargingStation {
     }
   }
 
-  async sendBootNotification() {
+  async sendBootNotification(): Promise<void> {
     try {
       await this.sendMessage(Utils.generateUUID(), this._bootNotificationMessage, Constants.OCPP_JSON_CALL_MESSAGE, 'BootNotification');
     } catch (error) {
@@ -615,7 +618,8 @@ export default class ChargingStation {
     }
   }
 
-  async sendStatusNotification(connectorId: number, status: string, errorCode = 'NoError') {
+  async sendStatusNotification(connectorId: number, status: ChargePointStatus, errorCode = 'NoError'): Promise<void> {
+    this.getConnector(connectorId).status = status;
     try {
       const payload = {
         connectorId,
@@ -1029,7 +1033,7 @@ export default class ChargingStation {
       this.getConnector(requestPayload.connectorId).transactionId = payload.transactionId;
       this.getConnector(requestPayload.connectorId).idTag = requestPayload.idTag;
       this.getConnector(requestPayload.connectorId).lastEnergyActiveImportRegisterValue = 0;
-      this.sendStatusNotification(requestPayload.connectorId, 'Charging');
+      this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.CHARGING);
       logger.info(this._logPrefix() + ' Transaction ' + payload.transactionId + ' STARTED on ' + this._stationInfo.name + '#' + requestPayload.connectorId + ' for idTag ' + requestPayload.idTag);
       if (this._stationInfo.powerSharedByConnectors) {
         this._stationInfo.powerDivider++;
@@ -1040,7 +1044,7 @@ export default class ChargingStation {
     } else {
       logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId + ' REJECTED with status ' + payload.idTagInfo.status + ', idTag ' + requestPayload.idTag);
       this._resetTransactionOnConnector(requestPayload.connectorId);
-      this.sendStatusNotification(requestPayload.connectorId, 'Available');
+      this.sendStatusNotification(requestPayload.connectorId, ChargePointStatus.AVAILABLE);
     }
   }
 
@@ -1057,7 +1061,7 @@ export default class ChargingStation {
       return;
     }
     if (payload.idTagInfo && payload.idTagInfo.status === 'Accepted') {
-      this.sendStatusNotification(transactionConnectorId, 'Available');
+      this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE);
       if (this._stationInfo.powerSharedByConnectors) {
         this._stationInfo.powerDivider--;
       }
diff --git a/src/types/ChargePointStatus.ts b/src/types/ChargePointStatus.ts
new file mode 100644 (file)
index 0000000..45bad01
--- /dev/null
@@ -0,0 +1,12 @@
+export enum ChargePointStatus {
+  AVAILABLE = 'Available',
+  PREPARING = 'Preparing',
+  CHARGING = 'Charging',
+  OCCUPIED = 'Occupied',
+  SUSPENDED_EVSE = 'SuspendedEVSE',
+  SUSPENDED_EV = 'SuspendedEV',
+  FINISHING = 'Finishing',
+  RESERVED = 'Reserved',
+  UNAVAILABLE = 'Unavailable',
+  FAULTED = 'Faulted',
+}
index dbbec6533120bec2316f1b536f3b5111b9f59cae..6c3a36c6ab2221199f4a354ea76cfc189c82d8eb 100644 (file)
@@ -1,4 +1,4 @@
-export interface MeasurandValues {
+export default interface MeasurandValues {
   L1: number;
   L2: number;
   L3: number;