| 1 | import { AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../../types/ocpp/Transaction'; |
| 2 | import { IncomingRequestCommand, 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, 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 Record<string, unknown>]; |
| 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.performanceStatistics.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 | /** |
| 72 | * Function that will receive the request's response |
| 73 | * |
| 74 | * @param {Record<string, unknown> | string} payload |
| 75 | * @param {Record<string, unknown>} requestPayload |
| 76 | */ |
| 77 | async function responseCallback(payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> { |
| 78 | if (self.chargingStation.getEnableStatistics()) { |
| 79 | self.chargingStation.performanceStatistics.addMessage(commandName, MessageType.CALL_RESULT_MESSAGE); |
| 80 | } |
| 81 | // Send the response |
| 82 | await self.ocppResponseService.handleResponse(commandName as RequestCommand, payload, requestPayload); |
| 83 | resolve(payload); |
| 84 | } |
| 85 | |
| 86 | /** |
| 87 | * Function that will receive the request's rejection |
| 88 | * |
| 89 | * @param {OCPPError} error |
| 90 | */ |
| 91 | function rejectCallback(error: OCPPError): void { |
| 92 | if (self.chargingStation.getEnableStatistics()) { |
| 93 | self.chargingStation.performanceStatistics.addMessage(commandName, MessageType.CALL_ERROR_MESSAGE); |
| 94 | } |
| 95 | logger.debug(`${self.chargingStation.logPrefix()} Error: %j occurred when calling command %s with parameters: %j`, error, commandName, commandParams); |
| 96 | // Build Exception |
| 97 | // eslint-disable-next-line no-empty-function |
| 98 | self.chargingStation.requests[messageId] = [() => { }, () => { }, {}]; |
| 99 | // Send error |
| 100 | reject(error); |
| 101 | } |
| 102 | }); |
| 103 | } |
| 104 | |
| 105 | public handleRequestError(commandName: RequestCommand, error: Error): void { |
| 106 | logger.error(this.chargingStation.logPrefix() + ' Send ' + commandName + ' error: %j', error); |
| 107 | throw error; |
| 108 | } |
| 109 | |
| 110 | public abstract sendHeartbeat(): Promise<void>; |
| 111 | public abstract sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string, chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string): Promise<BootNotificationResponse>; |
| 112 | public abstract sendStatusNotification(connectorId: number, status: ChargePointStatus, errorCode?: ChargePointErrorCode): Promise<void>; |
| 113 | public abstract sendAuthorize(idTag?: string): Promise<AuthorizeResponse>; |
| 114 | public abstract sendStartTransaction(connectorId: number, idTag?: string): Promise<StartTransactionResponse>; |
| 115 | public abstract sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason?: StopTransactionReason): Promise<StopTransactionResponse>; |
| 116 | public abstract sendMeterValues(connectorId: number, transactionId: number, interval: number, self: OCPPRequestService): Promise<void>; |
| 117 | public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise<unknown>; |
| 118 | } |