| 1 | import { AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../../types/ocpp/Transaction'; |
| 2 | import { IncomingRequestCommand, Request, RequestCommand } from '../../types/ocpp/Requests'; |
| 3 | |
| 4 | import { BootNotificationResponse } from '../../types/ocpp/Responses'; |
| 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'; |
| 10 | import { MessageType } from '../../types/ocpp/MessageType'; |
| 11 | import OCPPError from '../OcppError'; |
| 12 | import OCPPResponseService from './OCPPResponseService'; |
| 13 | import logger from '../../utils/Logger'; |
| 14 | |
| 15 | export default abstract class OCPPRequestService { |
| 16 | public chargingStation: ChargingStation; |
| 17 | protected ocppResponseService: OCPPResponseService; |
| 18 | |
| 19 | constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) { |
| 20 | this.chargingStation = chargingStation; |
| 21 | this.ocppResponseService = ocppResponseService; |
| 22 | } |
| 23 | |
| 24 | public async sendMessage(messageId: string, commandParams: any, messageType: MessageType = MessageType.CALL_RESULT_MESSAGE, commandName: RequestCommand | IncomingRequestCommand): Promise<any> { |
| 25 | // eslint-disable-next-line @typescript-eslint/no-this-alias |
| 26 | const self = this; |
| 27 | // Send a message through wsConnection |
| 28 | return new Promise((resolve: (value?: any | PromiseLike<any>) => void, reject: (reason?: any) => void) => { |
| 29 | let messageToSend: string; |
| 30 | // Type of message |
| 31 | switch (messageType) { |
| 32 | // Request |
| 33 | case MessageType.CALL_MESSAGE: |
| 34 | // Build request |
| 35 | this.chargingStation.requests[messageId] = [responseCallback, rejectCallback, commandParams] as Request; |
| 36 | messageToSend = JSON.stringify([messageType, messageId, commandName, commandParams]); |
| 37 | break; |
| 38 | // Response |
| 39 | case MessageType.CALL_RESULT_MESSAGE: |
| 40 | // Build response |
| 41 | messageToSend = JSON.stringify([messageType, messageId, commandParams]); |
| 42 | break; |
| 43 | // Error Message |
| 44 | case MessageType.CALL_ERROR_MESSAGE: |
| 45 | // Build Error Message |
| 46 | messageToSend = JSON.stringify([messageType, messageId, commandParams.code ? commandParams.code : ErrorType.GENERIC_ERROR, commandParams.message ? commandParams.message : '', commandParams.details ? commandParams.details : {}]); |
| 47 | break; |
| 48 | } |
| 49 | // Check if wsConnection opened and charging station registered |
| 50 | if (this.chargingStation.isWebSocketOpen() && (this.chargingStation.isRegistered() || commandName === RequestCommand.BOOT_NOTIFICATION)) { |
| 51 | if (this.chargingStation.getEnableStatistics()) { |
| 52 | this.chargingStation.statistics.addMessage(commandName, messageType); |
| 53 | } |
| 54 | // Yes: Send Message |
| 55 | this.chargingStation.wsConnection.send(messageToSend); |
| 56 | } else if (commandName !== RequestCommand.BOOT_NOTIFICATION) { |
| 57 | // Buffer it |
| 58 | this.chargingStation.addToMessageQueue(messageToSend); |
| 59 | // Reject it |
| 60 | return rejectCallback(new OCPPError(commandParams.code ? commandParams.code : ErrorType.GENERIC_ERROR, commandParams.message ? commandParams.message : `WebSocket closed for message id '${messageId}' with content '${messageToSend}', message buffered`, commandParams.details ? commandParams.details : {})); |
| 61 | } |
| 62 | // Response? |
| 63 | if (messageType === MessageType.CALL_RESULT_MESSAGE) { |
| 64 | // Yes: send Ok |
| 65 | resolve(); |
| 66 | } else if (messageType === MessageType.CALL_ERROR_MESSAGE) { |
| 67 | // Send timeout |
| 68 | setTimeout(() => rejectCallback(new OCPPError(commandParams.code ? commandParams.code : ErrorType.GENERIC_ERROR, commandParams.message ? commandParams.message : `Timeout for message id '${messageId}' with content '${messageToSend}'`, commandParams.details ? commandParams.details : {})), Constants.OCPP_ERROR_TIMEOUT); |
| 69 | } |
| 70 | |
| 71 | // Function that will receive the request's response |
| 72 | async function responseCallback(payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> { |
| 73 | if (self.chargingStation.getEnableStatistics()) { |
| 74 | self.chargingStation.statistics.addMessage(commandName, messageType); |
| 75 | } |
| 76 | // Send the response |
| 77 | await self.ocppResponseService.handleResponse(commandName as RequestCommand, payload, requestPayload); |
| 78 | resolve(payload); |
| 79 | } |
| 80 | |
| 81 | // Function that will receive the request's rejection |
| 82 | function rejectCallback(error: OCPPError): void { |
| 83 | if (self.chargingStation.getEnableStatistics()) { |
| 84 | self.chargingStation.statistics.addMessage(commandName, messageType); |
| 85 | } |
| 86 | logger.debug(`${self.chargingStation.logPrefix()} Error: %j occurred when calling command %s with parameters: %j`, error, commandName, commandParams); |
| 87 | // Build Exception |
| 88 | // eslint-disable-next-line no-empty-function |
| 89 | self.chargingStation.requests[messageId] = [() => { }, () => { }, {}]; |
| 90 | // Send error |
| 91 | reject(error); |
| 92 | } |
| 93 | }); |
| 94 | } |
| 95 | |
| 96 | public handleRequestError(commandName: RequestCommand, error: Error): void { |
| 97 | logger.error(this.chargingStation.logPrefix() + ' Send ' + commandName + ' error: %j', error); |
| 98 | throw error; |
| 99 | } |
| 100 | |
| 101 | public abstract sendHeartbeat(): Promise<void>; |
| 102 | public abstract sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string, chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string): Promise<BootNotificationResponse>; |
| 103 | public abstract sendStatusNotification(connectorId: number, status: ChargePointStatus, errorCode?: ChargePointErrorCode): Promise<void>; |
| 104 | public abstract sendAuthorize(idTag?: string): Promise<AuthorizeResponse>; |
| 105 | public abstract sendStartTransaction(connectorId: number, idTag?: string): Promise<StartTransactionResponse>; |
| 106 | public abstract sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason?: StopTransactionReason): Promise<StopTransactionResponse>; |
| 107 | public abstract sendMeterValues(connectorId: number, transactionId: number, interval: number, self: OCPPRequestService): Promise<void>; |
| 108 | public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise<unknown>; |
| 109 | } |