import { DefaultResponse } from '../../../types/ocpp/Responses';
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { IncomingRequestHandler } from '../../../types/ocpp/Requests';
-import { MessageType } from '../../../types/ocpp/MessageType';
+import { JsonType } from '../../../types/JsonType';
import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
import { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
-import OCPPError from '../OCPPError';
+import OCPPError from '../../../exception/OCPPError';
import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
import { URL } from 'url';
import Utils from '../../../utils/Utils';
export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
- constructor(chargingStation: ChargingStation) {
+ public constructor(chargingStation: ChargingStation) {
+ if (new.target?.name === 'OCPP16IncomingRequestService') {
+ throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+ }
super(chargingStation);
this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
[OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
]);
}
- public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record<string, unknown>): Promise<void> {
- let response: Record<string, unknown>;
- if (this.incomingRequestHandlers.has(commandName)) {
- try {
- // Call the method to build the response
- response = await this.incomingRequestHandlers.get(commandName)(commandPayload);
- } catch (error) {
- // Log
- logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
- throw error;
+ public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: JsonType): Promise<void> {
+ let result: JsonType;
+ if (this.chargingStation.getOcppStrictCompliance() && (this.chargingStation.isInPendingState()
+ && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION))) {
+ throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is in pending state on the central server`, commandName);
+ }
+ if (this.chargingStation.isRegistered() || (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())) {
+ if (this.incomingRequestHandlers.has(commandName)) {
+ try {
+ // Call the method to build the result
+ result = await this.incomingRequestHandlers.get(commandName)(commandPayload);
+ } catch (error) {
+ // Log
+ logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
+ throw error;
+ }
+ } else {
+ // Throw exception
+ throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
}
} else {
- // Throw exception
- throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
+ throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is not registered on the central server.`, commandName);
}
- // Send the built response
- await this.chargingStation.ocppRequestService.sendMessage(messageId, response, MessageType.CALL_RESULT_MESSAGE, commandName);
+ // Send the built result
+ await this.chargingStation.ocppRequestService.sendResult(messageId, result, commandName);
}
// Simulate charging station restart
if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
let authorized = false;
if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
- && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
+ && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag = commandPayload.idTag;
this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized = true;
authorized = true;
- }
- if (!authorized && this.chargingStation.getMayAuthorizeAtRemoteStart()) {
+ } else if (this.chargingStation.getMayAuthorizeAtRemoteStart()) {
const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(transactionConnectorId, commandPayload.idTag);
if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
authorized = true;
}
+ } else {
+ logger.warn(`${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`);
}
if (authorized) {
// Authorization successful, start transaction
setTimeout(() => {
this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel,
this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
- this.chargingStation.getBootNotificationRequest().firmwareVersion).catch(() => { /* This is intentional */ });
+ this.chargingStation.getBootNotificationRequest().firmwareVersion, this.chargingStation.getBootNotificationRequest().chargePointSerialNumber,
+ this.chargingStation.getBootNotificationRequest().iccid, this.chargingStation.getBootNotificationRequest().imsi,
+ this.chargingStation.getBootNotificationRequest().meterSerialNumber, this.chargingStation.getBootNotificationRequest().meterType,
+ { triggerMessage: true }).catch(() => { /* This is intentional */ });
}, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
case MessageTrigger.Heartbeat:
setTimeout(() => {
- this.chargingStation.ocppRequestService.sendHeartbeat().catch(() => { /* This is intentional */ });
+ this.chargingStation.ocppRequestService.sendHeartbeat({ triggerMessage: true }).catch(() => { /* This is intentional */ });
}, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
default: