From: Jérôme Benoit Date: Thu, 8 Sep 2022 16:21:26 +0000 (+0200) Subject: UI Protocol: add Authorize command support X-Git-Tag: v1.1.72~10 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=1984f1944eeb7468c2f3adbf03b83fbc98910dff;p=e-mobility-charging-stations-simulator.git UI Protocol: add Authorize command support And also fix connector status init Reference #169 Signed-off-by: Jérôme Benoit --- diff --git a/src/assets/ui-protocol/Insomnia_CSSimulatorUIProtocol.json b/src/assets/ui-protocol/Insomnia_CSSimulatorUIProtocol.json index 61dded03..5478e0fe 100644 --- a/src/assets/ui-protocol/Insomnia_CSSimulatorUIProtocol.json +++ b/src/assets/ui-protocol/Insomnia_CSSimulatorUIProtocol.json @@ -1,13 +1,13 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2022-09-05T20:42:59.578Z", + "__export_date": "2022-09-08T16:13:30.328Z", "__export_source": "insomnia.desktop.app:v2022.5.1", "resources": [ { "_id": "req_606dcee139984772877def40fcbb5c76", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662410526425, + "modified": 1662652240497, "created": 1661789624987, "url": "{{baseUrl}}/{{protocol}}/{{version}}/listChargingStations", "name": "listChargingStations", @@ -52,7 +52,7 @@ { "_id": "req_7d5f9506e7ac49208a4f960a7740663e", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662373634204, + "modified": 1662653581303, "created": 1661789624990, "url": "{{baseUrl}}/{{protocol}}/{{version}}/startSimulator", "name": "startSimulator", @@ -87,7 +87,7 @@ { "_id": "req_59056be11534481c80a0b0da32e2a06a", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662367707319, + "modified": 1662653585962, "created": 1661789624994, "url": "{{baseUrl}}/{{protocol}}/{{version}}/stopSimulator", "name": "stopSimulator", @@ -122,7 +122,7 @@ { "_id": "req_aad7fd6db4c64869b60048b915010efc", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662372497848, + "modified": 1662649189382, "created": 1661789624998, "url": "{{baseUrl}}/{{protocol}}/{{version}}/startChargingStation", "name": "startChargingStation", @@ -160,7 +160,7 @@ { "_id": "req_d72d91cf3fb044179b8ae9d92a74f99c", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662372491437, + "modified": 1662653577920, "created": 1661789625002, "url": "{{baseUrl}}/{{protocol}}/{{version}}/stopChargingStation", "name": "stopChargingStation", @@ -198,7 +198,7 @@ { "_id": "req_747f458d196f4681b5fe15204b0067aa", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662367716472, + "modified": 1662653576909, "created": 1661789625005, "url": "{{baseUrl}}/{{protocol}}/{{version}}/openConnection", "name": "openConnection", @@ -236,7 +236,7 @@ { "_id": "req_401e6a62a33c4b6c90aaa2e019daab6d", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662367720232, + "modified": 1662653575192, "created": 1661789625014, "url": "{{baseUrl}}/{{protocol}}/{{version}}/closeConnection", "name": "closeConnection", @@ -274,7 +274,7 @@ { "_id": "req_2f757efe92fb4936ad4fa4b6763f9293", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662367718288, + "modified": 1662653573947, "created": 1661789625017, "url": "{{baseUrl}}/{{protocol}}/{{version}}/startTransaction", "name": "startTransaction", @@ -312,7 +312,7 @@ { "_id": "req_7c285fb6cb6948a08235a6c73cbeb1f9", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662367694077, + "modified": 1662653572192, "created": 1661789625020, "url": "{{baseUrl}}/{{protocol}}/{{version}}/stopTransaction", "name": "stopTransaction", @@ -320,7 +320,7 @@ "method": "POST", "body": { "mimeType": "application/json", - "text": "{\n\t\"hashIds\": [\n\t\t\"0058d8b50e422cce5bbd0c0a4ad13d5d657e8a88670dcf04c1b2b563fea3db5b96a3686278b374ed050e21baef89060e\"\n\t],\n\t\"transactionId\": 926436595\n}" + "text": "{\n\t\"hashIds\": [\n\t\t\"0058d8b50e422cce5bbd0c0a4ad13d5d657e8a88670dcf04c1b2b563fea3db5b96a3686278b374ed050e21baef89060e\"\n\t],\n\t\"transactionId\": 1906670842\n}" }, "parameters": [], "headers": [ @@ -350,7 +350,7 @@ { "_id": "req_b33c704fe3464dc5a5d3694abd9320d0", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662372502338, + "modified": 1662653571010, "created": 1661803778569, "url": "{{baseUrl}}/{{protocol}}/{{version}}/startAutomaticTransactionGenerator", "name": "startAutomaticTransactionGenerator", @@ -388,7 +388,7 @@ { "_id": "req_24c1c55fe3ba4ddb94702408f21a64df", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662372479288, + "modified": 1662653569672, "created": 1661803846882, "url": "{{baseUrl}}/{{protocol}}/{{version}}/stopAutomaticTransactionGenerator", "name": "stopAutomaticTransactionGenerator", @@ -426,7 +426,7 @@ { "_id": "req_6a78267706094fb59d85ed1531e07a55", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662410523458, + "modified": 1662653568405, "created": 1662330215407, "url": "{{baseUrl}}/{{protocol}}/{{version}}/statusNotification", "name": "statusNotification", @@ -464,7 +464,7 @@ { "_id": "req_61efafe9f4a14c268b948b9f9c5c4195", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", - "modified": 1662410531123, + "modified": 1662653565100, "created": 1662409405256, "url": "{{baseUrl}}/{{protocol}}/{{version}}/heartbeat", "name": "heartbeat", @@ -499,6 +499,44 @@ "settingFollowRedirects": "global", "_type": "request" }, + { + "_id": "req_9633f79d949d491e8b6892eed08bd198", + "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", + "modified": 1662653567170, + "created": 1662648910935, + "url": "{{baseUrl}}/{{protocol}}/{{version}}/authorize", + "name": "authorize", + "description": "", + "method": "POST", + "body": { + "mimeType": "application/json", + "text": "{\n\t\"hashIds\": [\n\t\t\"0058d8b50e422cce5bbd0c0a4ad13d5d657e8a88670dcf04c1b2b563fea3db5b96a3686278b374ed050e21baef89060e\",\n\t\t\"331d024fea36e3e2483a0e5dc9376234241c8c099ad201a441437b23622c308555183f37cbc84a1818c1c45aaae50896\"\n\t],\n\t\"idTag\": \"test\"\n}" + }, + "parameters": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json", + "id": "pair_3224616dd6604605a1e48b71f6e9f795" + } + ], + "authentication": { + "type": "basic", + "useISO88591": false, + "disabled": false, + "username": "{{username}}", + "password": "{{password}}" + }, + "metaSortKey": -999999450, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, { "_id": "env_74b29d59b9f04298b97fc9750476a4ca", "parentId": "wrk_d64b10b1e0c14563a80484ee684b5205", diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index bbe294b6..d7b67e6a 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -1218,7 +1218,11 @@ export default class ChargingStation { } // Initialize transaction attributes on connectors for (const connectorId of this.connectors.keys()) { - if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === false) { + if ( + connectorId > 0 && + (this.getConnectorStatus(connectorId).transactionStarted === undefined || + this.getConnectorStatus(connectorId).transactionStarted === false) + ) { this.initializeConnectorStatus(connectorId); } } diff --git a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts index e36650bb..154e1afb 100644 --- a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts +++ b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts @@ -8,6 +8,8 @@ import { import type { HeartbeatResponse, StatusNotificationResponse } from '../types/ocpp/Responses'; import { AuthorizationStatus, + AuthorizeRequest, + AuthorizeResponse, StartTransactionRequest, StartTransactionResponse, StopTransactionRequest, @@ -31,6 +33,7 @@ const moduleName = 'ChargingStationWorkerBroadcastChannel'; type CommandResponse = | StartTransactionResponse | StopTransactionResponse + | AuthorizeResponse | StatusNotificationResponse | HeartbeatResponse; @@ -65,10 +68,7 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca this.chargingStation.ocppRequestService.requestHandler< StartTransactionRequest, StartTransactionResponse - >(this.chargingStation, RequestCommand.START_TRANSACTION, { - connectorId: requestPayload.connectorId, - idTag: requestPayload.idTag, - }), + >(this.chargingStation, RequestCommand.START_TRANSACTION, requestPayload), ], [ BroadcastChannelProcedureName.STOP_TRANSACTION, @@ -77,13 +77,11 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca StopTransactionRequest, StartTransactionResponse >(this.chargingStation, RequestCommand.STOP_TRANSACTION, { - transactionId: requestPayload.transactionId, + ...requestPayload, meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId( requestPayload.transactionId, true ), - idTag: requestPayload.idTag, - reason: requestPayload.reason, }), ], [ @@ -96,35 +94,29 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca (requestPayload?: BroadcastChannelRequestPayload) => this.chargingStation.stopAutomaticTransactionGenerator(requestPayload.connectorIds), ], + [ + BroadcastChannelProcedureName.AUTHORIZE, + async (requestPayload?: BroadcastChannelRequestPayload) => + this.chargingStation.ocppRequestService.requestHandler< + AuthorizeRequest, + AuthorizeResponse + >(this.chargingStation, RequestCommand.AUTHORIZE, requestPayload), + ], [ BroadcastChannelProcedureName.STATUS_NOTIFICATION, async (requestPayload?: BroadcastChannelRequestPayload) => this.chargingStation.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(this.chargingStation, RequestCommand.STATUS_NOTIFICATION, { - connectorId: requestPayload.connectorId, - errorCode: requestPayload.errorCode, - status: requestPayload.status, - ...(requestPayload.info && { info: requestPayload.info }), - ...(requestPayload.timestamp && { timestamp: requestPayload.timestamp }), - ...(requestPayload.vendorId && { vendorId: requestPayload.vendorId }), - ...(requestPayload.vendorErrorCode && { - vendorErrorCode: requestPayload.vendorErrorCode, - }), - }), + >(this.chargingStation, RequestCommand.STATUS_NOTIFICATION, requestPayload), ], [ BroadcastChannelProcedureName.HEARTBEAT, - async (requestPayload?: BroadcastChannelRequestPayload) => { - delete requestPayload.hashId; - delete requestPayload.hashIds; - delete requestPayload.connectorIds; - return this.chargingStation.ocppRequestService.requestHandler< + async (requestPayload?: BroadcastChannelRequestPayload) => + this.chargingStation.ocppRequestService.requestHandler< HeartbeatRequest, HeartbeatResponse - >(this.chargingStation, RequestCommand.HEARTBEAT, requestPayload); - }, + >(this.chargingStation, RequestCommand.HEARTBEAT, requestPayload), ], ]); this.chargingStation = chargingStation; @@ -165,10 +157,24 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca status: ResponseStatus.SUCCESS, }; } else { - responsePayload = { - hashId: this.chargingStation.stationInfo.hashId, - status: this.commandResponseToResponseStatus(command, commandResponse as CommandResponse), - }; + const responseStatus = this.commandResponseToResponseStatus( + command, + commandResponse as CommandResponse + ); + if (responseStatus === ResponseStatus.SUCCESS) { + responsePayload = { + hashId: this.chargingStation.stationInfo.hashId, + status: responseStatus, + }; + } else { + responsePayload = { + hashId: this.chargingStation.stationInfo.hashId, + status: responseStatus, + command, + requestPayload, + commandResponse: commandResponse as CommandResponse, + }; + } } } catch (error) { logger.error( @@ -201,11 +207,24 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca requestPayload: BroadcastChannelRequestPayload ): Promise { if (this.commandHandlers.has(command) === true) { + this.cleanRequestPayload(command, requestPayload); return this.commandHandlers.get(command)(requestPayload); } throw new BaseError(`Unknown worker broadcast channel command: ${command}`); } + private cleanRequestPayload( + command: BroadcastChannelProcedureName, + requestPayload: BroadcastChannelRequestPayload + ): void { + delete requestPayload.hashId; + delete requestPayload.hashIds; + [ + BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR, + BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR, + ].includes(command) === false && delete requestPayload.connectorIds; + } + private commandResponseToResponseStatus( command: BroadcastChannelProcedureName, commandResponse: CommandResponse @@ -213,9 +232,14 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca switch (command) { case BroadcastChannelProcedureName.START_TRANSACTION: case BroadcastChannelProcedureName.STOP_TRANSACTION: + case BroadcastChannelProcedureName.AUTHORIZE: if ( - (commandResponse as StartTransactionResponse | StopTransactionResponse)?.idTagInfo - ?.status === AuthorizationStatus.ACCEPTED + ( + commandResponse as + | StartTransactionResponse + | StopTransactionResponse + | AuthorizeResponse + )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED ) { return ResponseStatus.SUCCESS; } diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 3129c993..89f8ffd0 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -289,20 +289,24 @@ export default class OCPP16ResponseService extends OCPPResponseService { break; } } + const isAuthorizeConnectorIdDefined = authorizeConnectorId !== undefined; if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) { - chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true; + isAuthorizeConnectorIdDefined && + (chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true); logger.debug( - `${chargingStation.logPrefix()} IdTag '${ - requestPayload.idTag - }' authorized on connector ${authorizeConnectorId}` + `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' accepted${ + isAuthorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : '' + }` ); } else { - chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false; - delete chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag; + if (isAuthorizeConnectorIdDefined) { + chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false; + delete chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag; + } logger.debug( - `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' refused with status '${ + `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' rejected with status '${ payload.idTagInfo.status - }' on connector ${authorizeConnectorId}` + }'${isAuthorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : ''}` ); } } diff --git a/src/charging-station/ui-server/ui-services/UIService001.ts b/src/charging-station/ui-server/ui-services/UIService001.ts index 57c34c22..4be6a2f2 100644 --- a/src/charging-station/ui-server/ui-services/UIService001.ts +++ b/src/charging-station/ui-server/ui-services/UIService001.ts @@ -43,6 +43,10 @@ export default class UIService001 extends AbstractUIService { ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR, this.handleStopAutomaticTransactionGenerator.bind(this) as ProtocolRequestHandler ); + this.requestHandlers.set( + ProcedureName.AUTHORIZE, + this.handleAuthorize.bind(this) as ProtocolRequestHandler + ); this.requestHandlers.set( ProcedureName.STATUS_NOTIFICATION, this.handleStatusNotification.bind(this) as ProtocolRequestHandler @@ -105,6 +109,10 @@ export default class UIService001 extends AbstractUIService { ); } + private handleAuthorize(uuid: string, payload: RequestPayload): void { + this.sendBroadcastChannelRequest(uuid, BroadcastChannelProcedureName.AUTHORIZE, payload); + } + private handleStatusNotification(uuid: string, payload: RequestPayload): void { this.sendBroadcastChannelRequest( uuid, diff --git a/src/types/UIProtocol.ts b/src/types/UIProtocol.ts index 4b96262b..75685141 100644 --- a/src/types/UIProtocol.ts +++ b/src/types/UIProtocol.ts @@ -38,6 +38,7 @@ export enum ProcedureName { STOP_TRANSACTION = 'stopTransaction', START_AUTOMATIC_TRANSACTION_GENERATOR = 'startAutomaticTransactionGenerator', STOP_AUTOMATIC_TRANSACTION_GENERATOR = 'stopAutomaticTransactionGenerator', + AUTHORIZE = 'authorize', STATUS_NOTIFICATION = 'statusNotification', HEARTBEAT = 'heartbeat', } diff --git a/src/types/WorkerBroadcastChannel.ts b/src/types/WorkerBroadcastChannel.ts index 788f7d68..be59789b 100644 --- a/src/types/WorkerBroadcastChannel.ts +++ b/src/types/WorkerBroadcastChannel.ts @@ -16,6 +16,7 @@ export enum BroadcastChannelProcedureName { STOP_TRANSACTION = 'stopTransaction', START_AUTOMATIC_TRANSACTION_GENERATOR = 'startAutomaticTransactionGenerator', STOP_AUTOMATIC_TRANSACTION_GENERATOR = 'stopAutomaticTransactionGenerator', + AUTHORIZE = 'authorize', STATUS_NOTIFICATION = 'statusNotification', HEARTBEAT = 'heartbeat', }