Commit | Line | Data |
---|---|---|
c0560973 | 1 | import { AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../../types/ocpp/Transaction'; |
caad9d6b | 2 | import { DiagnosticsStatus, IncomingRequestCommand, RequestCommand, SendParams } from '../../types/ocpp/Requests'; |
c0560973 | 3 | |
efa43e52 | 4 | import { BootNotificationResponse } from '../../types/ocpp/Responses'; |
c0560973 JB |
5 | import { ChargePointErrorCode } from '../../types/ocpp/ChargePointErrorCode'; |
6 | import { ChargePointStatus } from '../../types/ocpp/ChargePointStatus'; | |
7 | import ChargingStation from '../ChargingStation'; | |
8 | import Constants from '../../utils/Constants'; | |
9 | import { ErrorType } from '../../types/ocpp/ErrorType'; | |
d1888640 | 10 | import { JsonType } from '../../types/JsonType'; |
c0560973 | 11 | import { MessageType } from '../../types/ocpp/MessageType'; |
fd0c36fa | 12 | import { MeterValue } from '../../types/ocpp/MeterValues'; |
e58068fd | 13 | import OCPPError from '../../exception/OCPPError'; |
c0560973 | 14 | import OCPPResponseService from './OCPPResponseService'; |
a6b3c6c3 | 15 | import PerformanceStatistics from '../../performance/PerformanceStatistics'; |
6d9abcc2 | 16 | import Utils from '../../utils/Utils'; |
bc464bb1 | 17 | import getLogger from '../../utils/Logger'; |
c0560973 JB |
18 | |
19 | export default abstract class OCPPRequestService { | |
20 | public chargingStation: ChargingStation; | |
21 | protected ocppResponseService: OCPPResponseService; | |
22 | ||
23 | constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) { | |
24 | this.chargingStation = chargingStation; | |
25 | this.ocppResponseService = ocppResponseService; | |
26 | } | |
27 | ||
d1888640 | 28 | public async sendMessage(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, |
caad9d6b JB |
29 | params: SendParams = { |
30 | skipBufferingOnError: false, | |
31 | triggerMessage: false | |
d1888640 | 32 | }): Promise<JsonType | OCPPError | string> { |
672fed6e JB |
33 | if ((this.chargingStation.isInUnknownState() && commandName === RequestCommand.BOOT_NOTIFICATION) |
34 | || (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState()) | |
73c4266d | 35 | || this.chargingStation.isInAcceptedState() || (this.chargingStation.isInPendingState() && params.triggerMessage)) { |
caad9d6b JB |
36 | // eslint-disable-next-line @typescript-eslint/no-this-alias |
37 | const self = this; | |
38 | // Send a message through wsConnection | |
39 | return Utils.promiseWithTimeout(new Promise((resolve, reject) => { | |
40 | const messageToSend = this.buildMessageToSend(messageId, messageData, messageType, commandName, responseCallback, rejectCallback); | |
41 | if (this.chargingStation.getEnableStatistics()) { | |
42 | this.chargingStation.performanceStatistics.addRequestStatistic(commandName, messageType); | |
6198eef3 | 43 | } |
caad9d6b JB |
44 | // Check if wsConnection opened |
45 | if (this.chargingStation.isWebSocketConnectionOpened()) { | |
46 | // Yes: Send Message | |
47 | const beginId = PerformanceStatistics.beginMeasure(commandName); | |
48 | // FIXME: Handle sending error | |
49 | this.chargingStation.wsConnection.send(messageToSend); | |
50 | PerformanceStatistics.endMeasure(commandName, beginId); | |
51 | } else if (!params.skipBufferingOnError) { | |
52 | // Buffer it | |
53 | this.chargingStation.bufferMessage(messageToSend); | |
d1888640 | 54 | const ocppError = new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messageData?.details as JsonType ?? {}); |
caad9d6b JB |
55 | if (messageType === MessageType.CALL_MESSAGE) { |
56 | // Reject it but keep the request in the cache | |
57 | return reject(ocppError); | |
58 | } | |
59 | return rejectCallback(ocppError, false); | |
60 | } else { | |
61 | // Reject it | |
d1888640 | 62 | return rejectCallback(new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messageData?.details as JsonType ?? {}), false); |
c0560973 | 63 | } |
caad9d6b JB |
64 | // Response? |
65 | if (messageType !== MessageType.CALL_MESSAGE) { | |
66 | // Yes: send Ok | |
67 | return resolve(messageData); | |
a4bc2942 | 68 | } |
c0560973 | 69 | |
caad9d6b JB |
70 | /** |
71 | * Function that will receive the request's response | |
72 | * | |
73 | * @param payload | |
74 | * @param requestPayload | |
75 | */ | |
d1888640 | 76 | async function responseCallback(payload: JsonType | string, requestPayload: JsonType): Promise<void> { |
caad9d6b JB |
77 | if (self.chargingStation.getEnableStatistics()) { |
78 | self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_RESULT_MESSAGE); | |
79 | } | |
80 | // Handle the request's response | |
81 | try { | |
82 | await self.ocppResponseService.handleResponse(commandName as RequestCommand, payload, requestPayload); | |
83 | resolve(payload); | |
84 | } catch (error) { | |
85 | reject(error); | |
86 | throw error; | |
87 | } finally { | |
88 | self.chargingStation.requests.delete(messageId); | |
89 | } | |
c0560973 | 90 | } |
caad9d6b JB |
91 | |
92 | /** | |
93 | * Function that will receive the request's error response | |
94 | * | |
95 | * @param error | |
96 | * @param requestStatistic | |
97 | */ | |
98 | function rejectCallback(error: OCPPError, requestStatistic = true): void { | |
99 | if (requestStatistic && self.chargingStation.getEnableStatistics()) { | |
100 | self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_ERROR_MESSAGE); | |
101 | } | |
bc464bb1 | 102 | getLogger().error(`${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, error, commandName, messageData); |
caad9d6b JB |
103 | self.chargingStation.requests.delete(messageId); |
104 | reject(error); | |
105 | } | |
d1888640 | 106 | }), Constants.OCPP_WEBSOCKET_TIMEOUT, new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, commandName, messageData?.details as JsonType ?? {}), () => { |
caad9d6b JB |
107 | messageType === MessageType.CALL_MESSAGE && this.chargingStation.requests.delete(messageId); |
108 | }); | |
caad9d6b | 109 | } |
672fed6e | 110 | throw new OCPPError(ErrorType.SECURITY_ERROR, `Cannot send command ${commandName} payload when the charging station is in ${this.chargingStation.getRegistrationStatus()} state on the central server`, commandName); |
c0560973 JB |
111 | } |
112 | ||
c7f95d16 | 113 | protected handleRequestError(commandName: RequestCommand, error: Error): void { |
bc464bb1 | 114 | getLogger().error(this.chargingStation.logPrefix() + ' Request command %s error: %j', commandName, error); |
c0560973 JB |
115 | throw error; |
116 | } | |
117 | ||
d1888640 JB |
118 | private buildMessageToSend(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, |
119 | responseCallback: (payload: JsonType | string, requestPayload: JsonType) => Promise<void>, | |
9239b49a | 120 | rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void): string { |
e7accadb JB |
121 | let messageToSend: string; |
122 | // Type of message | |
123 | switch (messageType) { | |
124 | // Request | |
125 | case MessageType.CALL_MESSAGE: | |
126 | // Build request | |
de3dbcf5 JB |
127 | this.chargingStation.requests.set(messageId, [responseCallback, rejectCallback, commandName, messageData]); |
128 | messageToSend = JSON.stringify([messageType, messageId, commandName, messageData]); | |
e7accadb JB |
129 | break; |
130 | // Response | |
131 | case MessageType.CALL_RESULT_MESSAGE: | |
132 | // Build response | |
de3dbcf5 | 133 | messageToSend = JSON.stringify([messageType, messageId, messageData]); |
e7accadb JB |
134 | break; |
135 | // Error Message | |
136 | case MessageType.CALL_ERROR_MESSAGE: | |
137 | // Build Error Message | |
de3dbcf5 | 138 | messageToSend = JSON.stringify([messageType, messageId, messageData?.code ?? ErrorType.GENERIC_ERROR, messageData?.message ?? '', messageData?.details ?? {}]); |
e7accadb JB |
139 | break; |
140 | } | |
141 | return messageToSend; | |
142 | } | |
143 | ||
caad9d6b JB |
144 | public abstract sendHeartbeat(params?: SendParams): Promise<void>; |
145 | public abstract sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string, chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string, params?: SendParams): Promise<BootNotificationResponse>; | |
c0560973 | 146 | public abstract sendStatusNotification(connectorId: number, status: ChargePointStatus, errorCode?: ChargePointErrorCode): Promise<void>; |
163547b1 | 147 | public abstract sendAuthorize(connectorId: number, idTag?: string): Promise<AuthorizeResponse>; |
c0560973 JB |
148 | public abstract sendStartTransaction(connectorId: number, idTag?: string): Promise<StartTransactionResponse>; |
149 | public abstract sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason?: StopTransactionReason): Promise<StopTransactionResponse>; | |
aef1b33a | 150 | public abstract sendMeterValues(connectorId: number, transactionId: number, interval: number): Promise<void>; |
fd0c36fa JB |
151 | public abstract sendTransactionBeginMeterValues(connectorId: number, transactionId: number, beginMeterValue: MeterValue): Promise<void>; |
152 | public abstract sendTransactionEndMeterValues(connectorId: number, transactionId: number, endMeterValue: MeterValue): Promise<void>; | |
47e22477 | 153 | public abstract sendDiagnosticsStatusNotification(diagnosticsStatus: DiagnosticsStatus): Promise<void>; |
d1888640 JB |
154 | public abstract sendResult(messageId: string, resultMessageData: JsonType, commandName: RequestCommand | IncomingRequestCommand): Promise<JsonType>; |
155 | public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise<JsonType>; | |
c0560973 | 156 | } |