Ensure 1:1 mapping between charging station and ATG instances
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ResponseService.ts
index 5b6a3feca3babbc40699c68b64e83a18d092c422..54815bd6b4eee8c46c1351cd4c0c658834a63155 100644 (file)
@@ -5,8 +5,9 @@ import { HeartbeatRequest, OCPP16RequestCommand, StatusNotificationRequest } fro
 import { HeartbeatResponse, OCPP16BootNotificationResponse, OCPP16RegistrationStatus, StatusNotificationResponse } from '../../../types/ocpp/1.6/Responses';
 import { MeterValuesRequest, MeterValuesResponse } from '../../../types/ocpp/1.6/MeterValues';
 
-import ChargingStation from '../../ChargingStation';
+import type ChargingStation from '../../ChargingStation';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
+import { JsonType } from '../../../types/JsonType';
 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
 import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
@@ -19,7 +20,10 @@ import logger from '../../../utils/Logger';
 export default class OCPP16ResponseService extends OCPPResponseService {
   private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
 
-  constructor(chargingStation: ChargingStation) {
+  public constructor(chargingStation: ChargingStation) {
+    if (new.target?.name === 'OCPP16ResponseService') {
+      throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+    }
     super(chargingStation);
     this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
       [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
@@ -32,7 +36,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
     ]);
   }
 
-  public async handleResponse(commandName: OCPP16RequestCommand, payload: Record<string, unknown> | string, requestPayload: Record<string, unknown>): Promise<void> {
+  public async handleResponse(commandName: OCPP16RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise<void> {
     if (this.chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) {
       if (this.responseHandlers.has(commandName)) {
         try {
@@ -46,7 +50,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
         throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request response payload ${JSON.stringify(payload, null, 2)}`, commandName);
       }
     } else {
-      throw new OCPPError(ErrorType.SECURITY_ERROR, `The charging station is not registered on the central server. ${commandName} cannot be not issued to handle request response payload ${JSON.stringify(payload, null, 2)}`, commandName);
+      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request response payload ${JSON.stringify(payload, null, 2)} while the charging station is not registered on the central server. `, commandName);
     }
   }
 
@@ -55,10 +59,12 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartBeatInterval, payload.interval.toString());
       this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartbeatInterval, payload.interval.toString(), { visible: false });
       this.chargingStation.heartbeatSetInterval ? this.chargingStation.restartHeartbeat() : this.chargingStation.startHeartbeat();
-    } else if (payload.status === OCPP16RegistrationStatus.PENDING) {
-      logger.info(this.chargingStation.logPrefix() + ' Charging station in pending state on the central server');
+    }
+    if (Object.values(OCPP16RegistrationStatus).includes(payload.status)) {
+      const logMsg = `${this.chargingStation.logPrefix()} Charging station in '${payload.status}' state on the central server`;
+      payload.status === OCPP16RegistrationStatus.REJECTED ? logger.warn(logMsg) : logger.info(logMsg);
     } else {
-      logger.warn(this.chargingStation.logPrefix() + ' Charging station rejected by the central server');
+      logger.error(this.chargingStation.logPrefix() + ' Charging station boot notification response received: %j with undefined registration status', payload);
     }
   }
 
@@ -180,7 +186,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       return;
     }
     if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
-      (this.chargingStation.getBeginEndMeterValues() && this.chargingStation.getOutOfOrderEndMeterValues())
+      (this.chargingStation.getBeginEndMeterValues() && !this.chargingStation.getOcppStrictCompliance() && this.chargingStation.getOutOfOrderEndMeterValues())
         && await this.chargingStation.ocppRequestService.sendTransactionEndMeterValues(transactionConnectorId, requestPayload.transactionId,
           OCPP16ServiceUtils.buildTransactionEndMeterValue(this.chargingStation, transactionConnectorId, requestPayload.meterStop));
       if (!this.chargingStation.isChargingStationAvailable() || !this.chargingStation.isConnectorAvailable(transactionConnectorId)) {