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 if (this.isResponse(messageEvent
.data
) === true) {
51 const [uuid
, command
, requestPayload
] = this.validateMessageEvent(messageEvent
)
52 .data
as BroadcastChannelRequest
;
54 if (requestPayload
?.hashIds
!== undefined || requestPayload
?.hashId
!== undefined) {
56 requestPayload
?.hashId
=== undefined &&
57 requestPayload
?.hashIds
?.includes(this.chargingStation
.stationInfo
.hashId
) === false
62 requestPayload
?.hashIds
=== undefined &&
63 requestPayload
?.hashId
!== this.chargingStation
.stationInfo
.hashId
67 if (requestPayload
?.hashId
!== undefined) {
69 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: 'hashId' field usage in PDU is deprecated, use 'hashIds' instead`
74 let responsePayload
: BroadcastChannelResponsePayload
;
75 let commandResponse
: CommandResponse
;
77 commandResponse
= await this.commandHandler(command
, requestPayload
);
78 if (commandResponse
=== undefined) {
80 hashId
: this.chargingStation
.stationInfo
.hashId
,
81 status: ResponseStatus
.SUCCESS
,
85 hashId
: this.chargingStation
.stationInfo
.hashId
,
86 status: this.commandResponseToResponseStatus(command
, commandResponse
),
91 `${this.chargingStation.logPrefix()} ${moduleName}.requestHandler: Handle request error:`,
95 hashId
: this.chargingStation
.stationInfo
.hashId
,
96 status: ResponseStatus
.FAILURE
,
100 errorMessage
: (error
as Error).message
,
101 errorStack
: (error
as Error).stack
,
102 errorDetails
: (error
as OCPPError
).details
,
105 this.sendResponse([uuid
, responsePayload
]);
108 private messageErrorHandler(messageEvent
: MessageEvent
): void {
110 `${this.chargingStation.logPrefix()} ${moduleName}.messageErrorHandler: Error at handling message:`,
115 private async commandHandler(
116 command
: BroadcastChannelProcedureName
,
117 requestPayload
: BroadcastChannelRequestPayload
118 ): Promise
<CommandResponse
| undefined> {
120 case BroadcastChannelProcedureName
.START_CHARGING_STATION
:
121 this.chargingStation
.start();
123 case BroadcastChannelProcedureName
.STOP_CHARGING_STATION
:
124 await this.chargingStation
.stop();
126 case BroadcastChannelProcedureName
.OPEN_CONNECTION
:
127 this.chargingStation
.openWSConnection();
129 case BroadcastChannelProcedureName
.CLOSE_CONNECTION
:
130 this.chargingStation
.closeWSConnection();
132 case BroadcastChannelProcedureName
.START_TRANSACTION
:
133 return this.chargingStation
.ocppRequestService
.requestHandler
<
134 StartTransactionRequest
,
135 StartTransactionResponse
136 >(this.chargingStation
, RequestCommand
.START_TRANSACTION
, {
137 connectorId
: requestPayload
.connectorId
,
138 idTag
: requestPayload
.idTag
,
140 case BroadcastChannelProcedureName
.STOP_TRANSACTION
:
141 return this.chargingStation
.ocppRequestService
.requestHandler
<
142 StopTransactionRequest
,
143 StopTransactionResponse
144 >(this.chargingStation
, RequestCommand
.STOP_TRANSACTION
, {
145 transactionId
: requestPayload
.transactionId
,
146 meterStop
: this.chargingStation
.getEnergyActiveImportRegisterByTransactionId(
147 requestPayload
.transactionId
,
150 idTag
: requestPayload
.idTag
,
151 reason
: requestPayload
.reason
,
153 case BroadcastChannelProcedureName
.START_AUTOMATIC_TRANSACTION_GENERATOR
:
154 this.chargingStation
.startAutomaticTransactionGenerator(requestPayload
.connectorIds
);
156 case BroadcastChannelProcedureName
.STOP_AUTOMATIC_TRANSACTION_GENERATOR
:
157 this.chargingStation
.stopAutomaticTransactionGenerator(requestPayload
.connectorIds
);
159 case BroadcastChannelProcedureName
.STATUS_NOTIFICATION
:
160 return this.chargingStation
.ocppRequestService
.requestHandler
<
161 StatusNotificationRequest
,
162 StatusNotificationResponse
163 >(this.chargingStation
, RequestCommand
.STATUS_NOTIFICATION
, {
164 connectorId
: requestPayload
.connectorId
,
165 errorCode
: requestPayload
.errorCode
,
166 status: requestPayload
.status,
167 ...(requestPayload
.info
&& { info
: requestPayload
.info
}),
168 ...(requestPayload
.timestamp
&& { timestamp
: requestPayload
.timestamp
}),
169 ...(requestPayload
.vendorId
&& { vendorId
: requestPayload
.vendorId
}),
170 ...(requestPayload
.vendorErrorCode
&& {
171 vendorErrorCode
: requestPayload
.vendorErrorCode
,
174 case BroadcastChannelProcedureName
.HEARTBEAT
:
175 delete requestPayload
.hashId
;
176 delete requestPayload
.hashIds
;
177 delete requestPayload
.connectorIds
;
178 return this.chargingStation
.ocppRequestService
.requestHandler
<
181 >(this.chargingStation
, RequestCommand
.HEARTBEAT
, requestPayload
);
183 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
184 throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
188 private commandResponseToResponseStatus(
189 command
: BroadcastChannelProcedureName
,
190 commandResponse
: CommandResponse
193 case BroadcastChannelProcedureName
.START_TRANSACTION
:
194 case BroadcastChannelProcedureName
.STOP_TRANSACTION
:
196 (commandResponse
as StartTransactionResponse
| StopTransactionResponse
)?.idTagInfo
197 ?.status === AuthorizationStatus
.ACCEPTED
199 return ResponseStatus
.SUCCESS
;
201 return ResponseStatus
.FAILURE
;
202 case BroadcastChannelProcedureName
.STATUS_NOTIFICATION
:
203 if (Utils
.isEmptyObject(commandResponse
) === true) {
204 return ResponseStatus
.SUCCESS
;
206 return ResponseStatus
.FAILURE
;
207 case BroadcastChannelProcedureName
.HEARTBEAT
:
208 if ('currentTime' in commandResponse
) {
209 return ResponseStatus
.SUCCESS
;
211 return ResponseStatus
.FAILURE
;
213 return ResponseStatus
.FAILURE
;