X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStationWorkerBroadcastChannel.ts;h=086278784cb5eb7b1f1e53286207c6d41314d03e;hb=b20eb107fed5d02d7c6317944c4aef034aef49b2;hp=7212f09d0cf7b6832f494ddf0fb0925a47bac440;hpb=4e3ff94d15f16cbeb7f65d14525bca7af3c551fd;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts index 7212f09d..08627878 100644 --- a/src/charging-station/ChargingStationWorkerBroadcastChannel.ts +++ b/src/charging-station/ChargingStationWorkerBroadcastChannel.ts @@ -1,21 +1,27 @@ +import BaseError from '../exception/BaseError'; import { RequestCommand } from '../types/ocpp/Requests'; import { + AuthorizationStatus, StartTransactionRequest, StartTransactionResponse, - StopTransactionReason, StopTransactionRequest, StopTransactionResponse, } from '../types/ocpp/Transaction'; import { BroadcastChannelProcedureName, BroadcastChannelRequest, + BroadcastChannelRequestPayload, + BroadcastChannelResponsePayload, + MessageEvent, } from '../types/WorkerBroadcastChannel'; -import ChargingStation from './ChargingStation'; +import { ResponseStatus } from '../ui/web/src/types/UIProtocol'; +import logger from '../utils/Logger'; +import type ChargingStation from './ChargingStation'; import WorkerBroadcastChannel from './WorkerBroadcastChannel'; const moduleName = 'ChargingStationWorkerBroadcastChannel'; -type MessageEvent = { data: unknown }; +type CommandResponse = StartTransactionResponse | StopTransactionResponse; export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChannel { private readonly chargingStation: ChargingStation; @@ -23,46 +29,131 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca constructor(chargingStation: ChargingStation) { super(); this.chargingStation = chargingStation; - this.onmessage = this.handleRequest.bind(this) as (message: MessageEvent) => void; + this.onmessage = this.requestHandler.bind(this) as (message: MessageEvent) => void; + this.onmessageerror = this.messageErrorHandler.bind(this) as (message: MessageEvent) => void; } - private async handleRequest(messageEvent: MessageEvent): Promise { - const [, command, payload] = messageEvent.data as BroadcastChannelRequest; - - if (payload.hashId !== this.chargingStation.hashId) { + private async requestHandler(messageEvent: MessageEvent): Promise { + if (this.isResponse(messageEvent.data)) { return; } + const [uuid, command, requestPayload] = this.validateMessageEvent(messageEvent) + .data as BroadcastChannelRequest; + + if (requestPayload?.hashIds !== undefined || requestPayload?.hashId !== undefined) { + if ( + requestPayload?.hashId === undefined && + requestPayload?.hashIds?.includes(this.chargingStation.stationInfo.hashId) === false + ) { + return; + } + if ( + requestPayload?.hashIds === undefined && + requestPayload?.hashId !== this.chargingStation.stationInfo.hashId + ) { + return; + } + if (requestPayload?.hashId !== undefined) { + logger.warn( + `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'hashId' field usage in PDU is deprecated, use 'hashIds' instead` + ); + } + } - // TODO: return a response stating the command success or failure + let responsePayload: BroadcastChannelResponsePayload; + let commandResponse: CommandResponse; + try { + commandResponse = await this.commandHandler(command, requestPayload); + if (commandResponse === undefined) { + responsePayload = { + hashId: this.chargingStation.stationInfo.hashId, + status: ResponseStatus.SUCCESS, + }; + } else { + responsePayload = { + hashId: this.chargingStation.stationInfo.hashId, + status: this.commandResponseToResponseStatus(commandResponse), + }; + } + } catch (error) { + logger.error( + `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`, + error + ); + responsePayload = { + hashId: this.chargingStation.stationInfo.hashId, + status: ResponseStatus.FAILURE, + command, + requestPayload, + commandResponse, + errorMessage: (error as Error).message, + errorStack: (error as Error).stack, + }; + } + this.sendResponse([uuid, responsePayload]); + } + + private messageErrorHandler(messageEvent: MessageEvent): void { + logger.error( + `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`, + { messageEvent } + ); + } + + private async commandHandler( + command: BroadcastChannelProcedureName, + requestPayload: BroadcastChannelRequestPayload + ): Promise { switch (command) { + case BroadcastChannelProcedureName.START_CHARGING_STATION: + this.chargingStation.start(); + break; + case BroadcastChannelProcedureName.STOP_CHARGING_STATION: + await this.chargingStation.stop(); + break; + case BroadcastChannelProcedureName.OPEN_CONNECTION: + this.chargingStation.openWSConnection(); + break; + case BroadcastChannelProcedureName.CLOSE_CONNECTION: + this.chargingStation.closeWSConnection(); + break; case BroadcastChannelProcedureName.START_TRANSACTION: - await this.chargingStation.ocppRequestService.requestHandler< + return this.chargingStation.ocppRequestService.requestHandler< StartTransactionRequest, StartTransactionResponse >(this.chargingStation, RequestCommand.START_TRANSACTION, { - connectorId: payload.connectorId, - idTag: payload.idTag, + connectorId: requestPayload.connectorId, + idTag: requestPayload.idTag, }); - break; case BroadcastChannelProcedureName.STOP_TRANSACTION: - await this.chargingStation.ocppRequestService.requestHandler< + return this.chargingStation.ocppRequestService.requestHandler< StopTransactionRequest, StopTransactionResponse >(this.chargingStation, RequestCommand.STOP_TRANSACTION, { - transactionId: payload.transactionId, + transactionId: requestPayload.transactionId, meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId( - payload.transactionId + requestPayload.transactionId, + true ), - idTag: this.chargingStation.getTransactionIdTag(payload.transactionId), - reason: StopTransactionReason.NONE, + idTag: this.chargingStation.getTransactionIdTag(requestPayload.transactionId), + ...(requestPayload.reason && { reason: requestPayload.reason }), }); + case BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR: + this.chargingStation.startAutomaticTransactionGenerator(requestPayload.connectorIds); break; - case BroadcastChannelProcedureName.START_CHARGING_STATION: - this.chargingStation.start(); - break; - case BroadcastChannelProcedureName.STOP_CHARGING_STATION: - await this.chargingStation.stop(); + case BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR: + this.chargingStation.stopAutomaticTransactionGenerator(requestPayload.connectorIds); break; + default: + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new BaseError(`Unknown worker broadcast channel command: ${command}`); + } + } + + private commandResponseToResponseStatus(commandResponse: CommandResponse): ResponseStatus { + if (commandResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { + return ResponseStatus.SUCCESS; } + return ResponseStatus.FAILURE; } }