1 import BaseError from
'../exception/BaseError';
2 import type OCPPError from
'../exception/OCPPError';
6 type StatusNotificationRequest
,
7 } from
'../types/ocpp/Requests';
8 import type { HeartbeatResponse
, StatusNotificationResponse
} from
'../types/ocpp/Responses';
11 StartTransactionRequest
,
12 StartTransactionResponse
,
13 StopTransactionRequest
,
14 StopTransactionResponse
,
15 } from
'../types/ocpp/Transaction';
17 BroadcastChannelProcedureName
,
18 BroadcastChannelRequest
,
19 BroadcastChannelRequestPayload
,
20 BroadcastChannelResponsePayload
,
22 } from
'../types/WorkerBroadcastChannel';
23 import { ResponseStatus
} from
'../ui/web/src/types/UIProtocol';
24 import logger from
'../utils/Logger';
25 import Utils from
'../utils/Utils';
26 import type ChargingStation from
'./ChargingStation';
27 import WorkerBroadcastChannel from
'./WorkerBroadcastChannel';
29 const moduleName
= 'ChargingStationWorkerBroadcastChannel';
31 type CommandResponse
=
32 | StartTransactionResponse
33 | StopTransactionResponse
34 | StatusNotificationResponse
37 export default class ChargingStationWorkerBroadcastChannel
extends WorkerBroadcastChannel
{
38 private readonly chargingStation
: ChargingStation
;
40 constructor(chargingStation
: ChargingStation
) {
42 this.chargingStation
= chargingStation
;
43 this.onmessage
= this.requestHandler
.bind(this) as (message
: MessageEvent
) => void;
44 this.onmessageerror
= this.messageErrorHandler
.bind(this) as (message
: MessageEvent
) => void;
47 private async requestHandler(messageEvent
: MessageEvent
): Promise
<void> {
48 const validatedMessageEvent
= this.validateMessageEvent(messageEvent
);
49 if (validatedMessageEvent
=== false) {
52 if (this.isResponse(validatedMessageEvent
.data
) === true) {
55 const [uuid
, command
, requestPayload
] = validatedMessageEvent
.data
as BroadcastChannelRequest
;
58 requestPayload
?.hashIds
!== undefined &&
59 requestPayload
?.hashIds
?.includes(this.chargingStation
.stationInfo
.hashId
) === false
63 if (requestPayload
?.hashId
!== undefined) {
65 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'hashId' field usage in PDU is deprecated, use 'hashIds' instead`
70 let responsePayload
: BroadcastChannelResponsePayload
;
71 let commandResponse
: CommandResponse
;
73 commandResponse
= await this.commandHandler(command
, requestPayload
);
74 if (commandResponse
=== undefined) {
76 hashId
: this.chargingStation
.stationInfo
.hashId
,
77 status: ResponseStatus
.SUCCESS
,
81 hashId
: this.chargingStation
.stationInfo
.hashId
,
82 status: this.commandResponseToResponseStatus(command
, commandResponse
),
87 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
91 hashId
: this.chargingStation
.stationInfo
.hashId
,
92 status: ResponseStatus
.FAILURE
,
96 errorMessage
: (error
as Error).message
,
97 errorStack
: (error
as Error).stack
,
98 errorDetails
: (error
as OCPPError
).details
,
101 this.sendResponse([uuid
, responsePayload
]);
104 private messageErrorHandler(messageEvent
: MessageEvent
): void {
106 `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`,
111 private async commandHandler(
112 command
: BroadcastChannelProcedureName
,
113 requestPayload
: BroadcastChannelRequestPayload
114 ): Promise
<CommandResponse
| undefined> {
116 case BroadcastChannelProcedureName
.START_CHARGING_STATION
:
117 this.chargingStation
.start();
119 case BroadcastChannelProcedureName
.STOP_CHARGING_STATION
:
120 await this.chargingStation
.stop();
122 case BroadcastChannelProcedureName
.OPEN_CONNECTION
:
123 this.chargingStation
.openWSConnection();
125 case BroadcastChannelProcedureName
.CLOSE_CONNECTION
:
126 this.chargingStation
.closeWSConnection();
128 case BroadcastChannelProcedureName
.START_TRANSACTION
:
129 return this.chargingStation
.ocppRequestService
.requestHandler
<
130 StartTransactionRequest
,
131 StartTransactionResponse
132 >(this.chargingStation
, RequestCommand
.START_TRANSACTION
, {
133 connectorId
: requestPayload
.connectorId
,
134 idTag
: requestPayload
.idTag
,
136 case BroadcastChannelProcedureName
.STOP_TRANSACTION
:
137 return this.chargingStation
.ocppRequestService
.requestHandler
<
138 StopTransactionRequest
,
139 StopTransactionResponse
140 >(this.chargingStation
, RequestCommand
.STOP_TRANSACTION
, {
141 transactionId
: requestPayload
.transactionId
,
142 meterStop
: this.chargingStation
.getEnergyActiveImportRegisterByTransactionId(
143 requestPayload
.transactionId
,
146 idTag
: requestPayload
.idTag
,
147 reason
: requestPayload
.reason
,
149 case BroadcastChannelProcedureName
.START_AUTOMATIC_TRANSACTION_GENERATOR
:
150 this.chargingStation
.startAutomaticTransactionGenerator(requestPayload
.connectorIds
);
152 case BroadcastChannelProcedureName
.STOP_AUTOMATIC_TRANSACTION_GENERATOR
:
153 this.chargingStation
.stopAutomaticTransactionGenerator(requestPayload
.connectorIds
);
155 case BroadcastChannelProcedureName
.STATUS_NOTIFICATION
:
156 return this.chargingStation
.ocppRequestService
.requestHandler
<
157 StatusNotificationRequest
,
158 StatusNotificationResponse
159 >(this.chargingStation
, RequestCommand
.STATUS_NOTIFICATION
, {
160 connectorId
: requestPayload
.connectorId
,
161 errorCode
: requestPayload
.errorCode
,
162 status: requestPayload
.status,
163 ...(requestPayload
.info
&& { info
: requestPayload
.info
}),
164 ...(requestPayload
.timestamp
&& { timestamp
: requestPayload
.timestamp
}),
165 ...(requestPayload
.vendorId
&& { vendorId
: requestPayload
.vendorId
}),
166 ...(requestPayload
.vendorErrorCode
&& {
167 vendorErrorCode
: requestPayload
.vendorErrorCode
,
170 case BroadcastChannelProcedureName
.HEARTBEAT
:
171 delete requestPayload
.hashId
;
172 delete requestPayload
.hashIds
;
173 delete requestPayload
.connectorIds
;
174 return this.chargingStation
.ocppRequestService
.requestHandler
<
177 >(this.chargingStation
, RequestCommand
.HEARTBEAT
, requestPayload
);
179 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
180 throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
184 private commandResponseToResponseStatus(
185 command
: BroadcastChannelProcedureName
,
186 commandResponse
: CommandResponse
189 case BroadcastChannelProcedureName
.START_TRANSACTION
:
190 case BroadcastChannelProcedureName
.STOP_TRANSACTION
:
192 (commandResponse
as StartTransactionResponse
| StopTransactionResponse
)?.idTagInfo
193 ?.status === AuthorizationStatus
.ACCEPTED
195 return ResponseStatus
.SUCCESS
;
197 return ResponseStatus
.FAILURE
;
198 case BroadcastChannelProcedureName
.STATUS_NOTIFICATION
:
199 if (Utils
.isEmptyObject(commandResponse
) === true) {
200 return ResponseStatus
.SUCCESS
;
202 return ResponseStatus
.FAILURE
;
203 case BroadcastChannelProcedureName
.HEARTBEAT
:
204 if ('currentTime' in commandResponse
) {
205 return ResponseStatus
.SUCCESS
;
207 return ResponseStatus
.FAILURE
;
209 return ResponseStatus
.FAILURE
;