1 import BaseError from
'../exception/BaseError';
2 import type OCPPError from
'../exception/OCPPError';
3 import { RequestCommand
, type StatusNotificationRequest
} from
'../types/ocpp/Requests';
4 import type { StatusNotificationResponse
} from
'../types/ocpp/Responses';
7 StartTransactionRequest
,
8 StartTransactionResponse
,
9 StopTransactionRequest
,
10 StopTransactionResponse
,
11 } from
'../types/ocpp/Transaction';
13 BroadcastChannelProcedureName
,
14 BroadcastChannelRequest
,
15 BroadcastChannelRequestPayload
,
16 BroadcastChannelResponsePayload
,
18 } from
'../types/WorkerBroadcastChannel';
19 import { ResponseStatus
} from
'../ui/web/src/types/UIProtocol';
20 import logger from
'../utils/Logger';
21 import Utils from
'../utils/Utils';
22 import type ChargingStation from
'./ChargingStation';
23 import WorkerBroadcastChannel from
'./WorkerBroadcastChannel';
25 const moduleName
= 'ChargingStationWorkerBroadcastChannel';
27 type CommandResponse
=
28 | StartTransactionResponse
29 | StopTransactionResponse
30 | StatusNotificationResponse
;
32 export default class ChargingStationWorkerBroadcastChannel
extends WorkerBroadcastChannel
{
33 private readonly chargingStation
: ChargingStation
;
35 constructor(chargingStation
: ChargingStation
) {
37 this.chargingStation
= chargingStation
;
38 this.onmessage
= this.requestHandler
.bind(this) as (message
: MessageEvent
) => void;
39 this.onmessageerror
= this.messageErrorHandler
.bind(this) as (message
: MessageEvent
) => void;
42 private async requestHandler(messageEvent
: MessageEvent
): Promise
<void> {
43 if (this.isResponse(messageEvent
.data
) === true) {
46 const [uuid
, command
, requestPayload
] = this.validateMessageEvent(messageEvent
)
47 .data
as BroadcastChannelRequest
;
49 if (requestPayload
?.hashIds
!== undefined || requestPayload
?.hashId
!== undefined) {
51 requestPayload
?.hashId
=== undefined &&
52 requestPayload
?.hashIds
?.includes(this.chargingStation
.stationInfo
.hashId
) === false
57 requestPayload
?.hashIds
=== undefined &&
58 requestPayload
?.hashId
!== this.chargingStation
.stationInfo
.hashId
62 if (requestPayload
?.hashId
!== undefined) {
64 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'hashId' field usage in PDU is deprecated, use 'hashIds' instead`
69 let responsePayload
: BroadcastChannelResponsePayload
;
70 let commandResponse
: CommandResponse
;
72 commandResponse
= await this.commandHandler(command
, requestPayload
);
73 if (commandResponse
=== undefined) {
75 hashId
: this.chargingStation
.stationInfo
.hashId
,
76 status: ResponseStatus
.SUCCESS
,
80 hashId
: this.chargingStation
.stationInfo
.hashId
,
81 status: this.commandResponseToResponseStatus(commandResponse
),
86 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
90 hashId
: this.chargingStation
.stationInfo
.hashId
,
91 status: ResponseStatus
.FAILURE
,
95 errorMessage
: (error
as Error).message
,
96 errorStack
: (error
as Error).stack
,
97 errorDetails
: (error
as OCPPError
).details
,
100 this.sendResponse([uuid
, responsePayload
]);
103 private messageErrorHandler(messageEvent
: MessageEvent
): void {
105 `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`,
110 private async commandHandler(
111 command
: BroadcastChannelProcedureName
,
112 requestPayload
: BroadcastChannelRequestPayload
113 ): Promise
<CommandResponse
| undefined> {
115 case BroadcastChannelProcedureName
.START_CHARGING_STATION
:
116 this.chargingStation
.start();
118 case BroadcastChannelProcedureName
.STOP_CHARGING_STATION
:
119 await this.chargingStation
.stop();
121 case BroadcastChannelProcedureName
.OPEN_CONNECTION
:
122 this.chargingStation
.openWSConnection();
124 case BroadcastChannelProcedureName
.CLOSE_CONNECTION
:
125 this.chargingStation
.closeWSConnection();
127 case BroadcastChannelProcedureName
.START_TRANSACTION
:
128 return this.chargingStation
.ocppRequestService
.requestHandler
<
129 StartTransactionRequest
,
130 StartTransactionResponse
131 >(this.chargingStation
, RequestCommand
.START_TRANSACTION
, {
132 connectorId
: requestPayload
.connectorId
,
133 idTag
: requestPayload
.idTag
,
135 case BroadcastChannelProcedureName
.STOP_TRANSACTION
:
136 return this.chargingStation
.ocppRequestService
.requestHandler
<
137 StopTransactionRequest
,
138 StopTransactionResponse
139 >(this.chargingStation
, RequestCommand
.STOP_TRANSACTION
, {
140 transactionId
: requestPayload
.transactionId
,
141 meterStop
: this.chargingStation
.getEnergyActiveImportRegisterByTransactionId(
142 requestPayload
.transactionId
,
145 idTag
: requestPayload
.idTag
,
146 reason
: requestPayload
.reason
,
148 case BroadcastChannelProcedureName
.START_AUTOMATIC_TRANSACTION_GENERATOR
:
149 this.chargingStation
.startAutomaticTransactionGenerator(requestPayload
.connectorIds
);
151 case BroadcastChannelProcedureName
.STOP_AUTOMATIC_TRANSACTION_GENERATOR
:
152 this.chargingStation
.stopAutomaticTransactionGenerator(requestPayload
.connectorIds
);
154 case BroadcastChannelProcedureName
.STATUS_NOTIFICATION
:
155 return this.chargingStation
.ocppRequestService
.requestHandler
<
156 StatusNotificationRequest
,
157 StatusNotificationResponse
158 >(this.chargingStation
, RequestCommand
.STATUS_NOTIFICATION
, {
159 connectorId
: requestPayload
.connectorId
,
160 errorCode
: requestPayload
.errorCode
,
161 status: requestPayload
.status,
162 ...(requestPayload
.info
&& { info
: requestPayload
.info
}),
163 ...(requestPayload
.timestamp
&& { timestamp
: requestPayload
.timestamp
}),
164 ...(requestPayload
.vendorId
&& { vendorId
: requestPayload
.vendorId
}),
165 ...(requestPayload
.vendorErrorCode
&& {
166 vendorErrorCode
: requestPayload
.vendorErrorCode
,
170 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
171 throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
175 private commandResponseToResponseStatus(commandResponse
: CommandResponse
): ResponseStatus
{
177 Utils
.isEmptyObject(commandResponse
) ||
178 commandResponse
?.idTagInfo
?.status === AuthorizationStatus
.ACCEPTED
180 return ResponseStatus
.SUCCESS
;
182 return ResponseStatus
.FAILURE
;