From 17991e8cf5f39801cdba8bd4682576c40e62dc4d Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 17 Jan 2021 17:44:15 +0100 Subject: [PATCH] Handle availability and registration properly. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- package-lock.json | 42 ++++++++++------ package.json | 6 +-- .../AutomaticTransactionGenerator.ts | 20 +++++--- src/charging-station/ChargingStation.ts | 48 +++++++++++-------- src/utils/Utils.ts | 2 +- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d7eb0fe..6f155762 100644 --- a/package-lock.json +++ b/package-lock.json @@ -299,9 +299,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -311,7 +311,7 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -343,6 +343,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -1857,9 +1863,9 @@ "dev": true }, "bufferutil": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz", - "integrity": "sha512-AtnG3W6M8B2n4xDQ5R+70EXvOpnXsFYg/AK2yTZd+HQ/oxAdz+GI+DvjmhBw3L0ole+LJ0ngqY4JMbDzkfNzhA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz", + "integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==", "optional": true, "requires": { "node-gyp-build": "^4.2.0" @@ -4117,13 +4123,13 @@ } }, "eslint": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", - "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4147,7 +4153,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -4243,6 +4249,12 @@ "type-check": "~0.4.0" } }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11153,9 +11165,9 @@ "dev": true }, "utf-8-validate": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz", - "integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.4.tgz", + "integrity": "sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==", "optional": true, "requires": { "node-gyp-build": "^4.2.0" diff --git a/package.json b/package.json index e3c0084c..d0cc70d2 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,8 @@ "ws": "^7.4.2" }, "optionalDependencies": { - "bufferutil": "^4.0.2", - "utf-8-validate": "^5.0.3" + "bufferutil": "^4.0.3", + "utf-8-validate": "^5.0.4" }, "devDependencies": { "@types/node": "^14.14.21", @@ -66,7 +66,7 @@ "@typescript-eslint/parser": "^4.13.0", "clinic": "^8.0.1", "cross-env": "^7.0.3", - "eslint": "^7.17.0", + "eslint": "^7.18.0", "grunt": "^1.3.0", "grunt-ts": "^6.0.0-beta.22", "mbt": "^1.1.0", diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index 6e33ae69..29f571e9 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -63,14 +63,22 @@ export default class AutomaticTransactionGenerator { async startConnector(connectorId: number): Promise { do { + if (this._timeToStop) { + logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made'); + break; + } + if (!this._chargingStation._isRegistered()) { + logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station is not registered'); + break; + } + if (!this._chargingStation._isChargingStationAvailable() || !this._chargingStation._isConnectorAvailable(connectorId)) { + logger.error(this._logPrefix(connectorId) + ' Entered in transaction loop while the charging station or connector is unavailable'); + break; + } const wait = Utils.getRandomInt(this._chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions, this._chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000; logger.info(this._logPrefix(connectorId) + ' wait for ' + Utils.milliSecondsToHHMMSS(wait)); await Utils.sleep(wait); - if (this._timeToStop) { - logger.debug(this._logPrefix(connectorId) + ' Entered in transaction loop while a request to stop it was made'); - break; - } const start = Math.random(); let skip = 0; if (start < this._chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) { @@ -114,7 +122,7 @@ export default class AutomaticTransactionGenerator { } // eslint-disable-next-line consistent-this - async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise { + private async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise { if (self._chargingStation.hasAuthorizedTags()) { const tagId = self._chargingStation.getRandomTagId(); logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId); @@ -125,7 +133,7 @@ export default class AutomaticTransactionGenerator { } // eslint-disable-next-line consistent-this - async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise { + private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise { return await self._chargingStation.sendStopTransaction(self._chargingStation.getConnector(connectorId).transactionId); } } diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 5bf359b6..8c0b04c1 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -304,6 +304,10 @@ export default class ChargingStation { return this.getConnector(id).availability === AvailabilityType.OPERATIVE; } + _isChargingStationAvailable(): boolean { + return this.getConnector(0).availability === AvailabilityType.OPERATIVE; + } + _getTemplateMaxNumberOfConnectors(): number { return Object.keys(this._stationInfo.Connectors).length; } @@ -1013,7 +1017,11 @@ export default class ChargingStation { return; } if (payload.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { - await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE); + if (!this._isChargingStationAvailable() || !this._isConnectorAvailable(transactionConnectorId)) { + await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.UNAVAILABLE); + } else { + await this.sendStatusNotification(transactionConnectorId, ChargePointStatus.AVAILABLE); + } if (this._stationInfo.powerSharedByConnectors) { this._stationInfo.powerDivider--; } @@ -1230,7 +1238,6 @@ export default class ChargingStation { return Constants.OCPP_CHARGING_PROFILE_RESPONSE_ACCEPTED; } - // FIXME: Handle properly the transaction started case handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): ChangeAvailabilityResponse { const connectorId: number = commandPayload.connectorId; if (!this.getConnector(connectorId)) { @@ -1245,13 +1252,12 @@ export default class ChargingStation { response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } this.getConnector(Utils.convertToInt(connector)).availability = commandPayload.type; - void this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus); + response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED && this.sendStatusNotification(Utils.convertToInt(connector), chargePointStatus); } return response; } else if (connectorId > 0 && (this.getConnector(0).availability === AvailabilityType.OPERATIVE || (this.getConnector(0).availability === AvailabilityType.INOPERATIVE && commandPayload.type === AvailabilityType.INOPERATIVE))) { if (this.getConnector(connectorId)?.transactionStarted) { this.getConnector(connectorId).availability = commandPayload.type; - void this.sendStatusNotification(connectorId, chargePointStatus); return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } this.getConnector(connectorId).availability = commandPayload.type; @@ -1263,23 +1269,27 @@ export default class ChargingStation { async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise { const transactionConnectorID: number = commandPayload.connectorId ? commandPayload.connectorId : 1; - if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) { - // Check if authorized - if (this._authorizedTags.find((value) => value === commandPayload.idTag)) { - await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); - // Authorization successful start transaction - await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + if (this._isChargingStationAvailable() && this._isConnectorAvailable(transactionConnectorID)) { + if (this._getAuthorizeRemoteTxRequests() && this._getLocalAuthListEnabled() && this.hasAuthorizedTags()) { + // Check if authorized + if (this._authorizedTags.find((value) => value === commandPayload.idTag)) { + await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); + // Authorization successful start transaction + await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); + logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_ACCEPTED; + } + logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_REJECTED; } - logger.error(this._logPrefix() + ' Remote starting transaction REJECTED, idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_REJECTED; + await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); + // No local authorization check required => start transaction + await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); + logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_ACCEPTED; } - await this.sendStatusNotification(transactionConnectorID, ChargePointStatus.PREPARING); - // No local authorization check required => start transaction - await this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + logger.error(this._logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); + return Constants.OCPP_RESPONSE_REJECTED; } async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise { diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 878d49d6..16cb7fa3 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -205,7 +205,7 @@ export default class Utils { } } if (!Utils.isUndefined(WebSocketCloseEventStatusString[code])) { - return WebSocketCloseEventStatusString[code]; + return WebSocketCloseEventStatusString[code] as string; } return '(Unknown)'; } -- 2.34.1