+ private getMaximumPower(stationInfo?: ChargingStationInfo): number {
+ const localStationInfo = stationInfo ?? this.stationInfo;
+ return (localStationInfo['maxPower'] as number) ?? localStationInfo.maximumPower;
+ }
+
+ private getMaximumAmperage(stationInfo: ChargingStationInfo): number | undefined {
+ const maximumPower = this.getMaximumPower(stationInfo);
+ switch (this.getCurrentOutType(stationInfo)) {
+ case CurrentType.AC:
+ return ACElectricUtils.amperagePerPhaseFromPower(
+ this.getNumberOfPhases(stationInfo),
+ maximumPower / this.getNumberOfConnectors(),
+ this.getVoltageOut(stationInfo)
+ );
+ case CurrentType.DC:
+ return DCElectricUtils.amperage(maximumPower, this.getVoltageOut(stationInfo));
+ }
+ }
+
+ private getAmperageLimitation(): number | undefined {
+ if (
+ this.stationInfo.amperageLimitationOcppKey &&
+ ChargingStationConfigurationUtils.getConfigurationKey(
+ this,
+ this.stationInfo.amperageLimitationOcppKey
+ )
+ ) {
+ return (
+ Utils.convertToInt(
+ ChargingStationConfigurationUtils.getConfigurationKey(
+ this,
+ this.stationInfo.amperageLimitationOcppKey
+ ).value
+ ) / ChargingStationUtils.getAmperageLimitationUnitDivider(this.stationInfo)
+ );
+ }
+ }
+
+ private getChargingProfilePowerLimit(connectorId: number): number | undefined {
+ let limit: number, matchingChargingProfile: ChargingProfile;
+ let chargingProfiles: ChargingProfile[] = [];
+ // Get charging profiles for connector and sort by stack level
+ chargingProfiles = this.getConnectorStatus(connectorId).chargingProfiles.sort(
+ (a, b) => b.stackLevel - a.stackLevel
+ );
+ // Get profiles on connector 0
+ if (this.getConnectorStatus(0).chargingProfiles) {
+ chargingProfiles.push(
+ ...this.getConnectorStatus(0).chargingProfiles.sort((a, b) => b.stackLevel - a.stackLevel)
+ );
+ }
+ if (!Utils.isEmptyArray(chargingProfiles)) {
+ const result = ChargingStationUtils.getLimitFromChargingProfiles(
+ chargingProfiles,
+ this.logPrefix()
+ );
+ if (!Utils.isNullOrUndefined(result)) {
+ limit = result.limit;
+ matchingChargingProfile = result.matchingChargingProfile;
+ switch (this.getCurrentOutType()) {
+ case CurrentType.AC:
+ limit =
+ matchingChargingProfile.chargingSchedule.chargingRateUnit ===
+ ChargingRateUnitType.WATT
+ ? limit
+ : ACElectricUtils.powerTotal(this.getNumberOfPhases(), this.getVoltageOut(), limit);
+ break;
+ case CurrentType.DC:
+ limit =
+ matchingChargingProfile.chargingSchedule.chargingRateUnit ===
+ ChargingRateUnitType.WATT
+ ? limit
+ : DCElectricUtils.power(this.getVoltageOut(), limit);
+ }
+ const connectorMaximumPower = this.getMaximumPower() / this.powerDivider;
+ if (limit > connectorMaximumPower) {
+ logger.error(
+ `${this.logPrefix()} Charging profile id ${
+ matchingChargingProfile.chargingProfileId
+ } limit is greater than connector id ${connectorId} maximum, dump charging profiles' stack: %j`,
+ this.getConnectorStatus(connectorId).chargingProfiles
+ );
+ limit = connectorMaximumPower;
+ }
+ }
+ }
+ return limit;
+ }
+
+ private async startMessageSequence(): Promise<void> {
+ if (this.stationInfo?.autoRegister) {
+ await this.ocppRequestService.requestHandler<
+ BootNotificationRequest,
+ BootNotificationResponse
+ >(
+ this,
+ RequestCommand.BOOT_NOTIFICATION,
+ {
+ chargePointModel: this.bootNotificationRequest.chargePointModel,
+ chargePointVendor: this.bootNotificationRequest.chargePointVendor,
+ chargeBoxSerialNumber: this.bootNotificationRequest.chargeBoxSerialNumber,
+ firmwareVersion: this.bootNotificationRequest.firmwareVersion,
+ chargePointSerialNumber: this.bootNotificationRequest.chargePointSerialNumber,
+ iccid: this.bootNotificationRequest.iccid,
+ imsi: this.bootNotificationRequest.imsi,
+ meterSerialNumber: this.bootNotificationRequest.meterSerialNumber,
+ meterType: this.bootNotificationRequest.meterType,
+ },
+ { skipBufferingOnError: true }
+ );
+ }
+ // Start WebSocket ping
+ this.startWebSocketPing();
+ // Start heartbeat
+ this.startHeartbeat();
+ // Initialize connectors status
+ for (const connectorId of this.connectors.keys()) {
+ if (connectorId === 0) {
+ continue;
+ } else if (
+ this.started === true &&
+ !this.getConnectorStatus(connectorId)?.status &&
+ this.getConnectorStatus(connectorId)?.bootStatus
+ ) {
+ // Send status in template at startup
+ await this.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(this, RequestCommand.STATUS_NOTIFICATION, {
+ connectorId,
+ status: this.getConnectorStatus(connectorId).bootStatus,
+ errorCode: ChargePointErrorCode.NO_ERROR,
+ });
+ this.getConnectorStatus(connectorId).status =
+ this.getConnectorStatus(connectorId).bootStatus;
+ } else if (
+ this.started === false &&
+ this.getConnectorStatus(connectorId)?.status &&
+ this.getConnectorStatus(connectorId)?.bootStatus
+ ) {
+ // Send status in template after reset
+ await this.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(this, RequestCommand.STATUS_NOTIFICATION, {
+ connectorId,
+ status: this.getConnectorStatus(connectorId).bootStatus,
+ errorCode: ChargePointErrorCode.NO_ERROR,
+ });
+ this.getConnectorStatus(connectorId).status =
+ this.getConnectorStatus(connectorId).bootStatus;
+ } else if (this.started === true && this.getConnectorStatus(connectorId)?.status) {
+ // Send previous status at template reload
+ await this.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(this, RequestCommand.STATUS_NOTIFICATION, {
+ connectorId,
+ status: this.getConnectorStatus(connectorId).status,
+ errorCode: ChargePointErrorCode.NO_ERROR,
+ });
+ } else {
+ // Send default status
+ await this.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(this, RequestCommand.STATUS_NOTIFICATION, {
+ connectorId,
+ status: ChargePointStatus.AVAILABLE,
+ errorCode: ChargePointErrorCode.NO_ERROR,
+ });
+ this.getConnectorStatus(connectorId).status = ChargePointStatus.AVAILABLE;
+ }
+ }
+ // Start the ATG
+ if (this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true) {
+ this.startAutomaticTransactionGenerator();
+ }