X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2FOCPPServiceUtils.ts;h=38f218ee35b46850154516c1c53572d4724f7a4d;hb=87bcd3b41c269bdb32468c766dca8d307689e8c2;hp=275494057a4500517ef4618f96a06268e527e0ac;hpb=b7bf49739aa3aafdcbe6a22243aa4cf0552c5972;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index 27549405..38f218ee 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -1,22 +1,22 @@ -import { readFileSync } from 'node:fs'; -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { readFileSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' -import type { DefinedError, ErrorObject, JSONSchemaType } from 'ajv'; -import { isDate } from 'date-fns'; +import type { DefinedError, ErrorObject, JSONSchemaType } from 'ajv' +import { isDate } from 'date-fns' -import { OCPP16Constants } from './1.6/OCPP16Constants'; -import { OCPP20Constants } from './2.0/OCPP20Constants'; -import { OCPPConstants } from './OCPPConstants'; -import { type ChargingStation, getConfigurationKey, getIdTagsFile } from '../../charging-station'; -import { BaseError, OCPPError } from '../../exception'; +import { + type ChargingStation, + getConfigurationKey, + getIdTagsFile +} from '../../charging-station/index.js' +import { BaseError, OCPPError } from '../../exception/index.js' import { AuthorizationStatus, type AuthorizeRequest, type AuthorizeResponse, ChargePointErrorCode, ChargingStationEvents, - type ConnectorStatus, type ConnectorStatusEnum, CurrentType, ErrorType, @@ -33,7 +33,9 @@ import { MeterValueMeasurand, MeterValuePhase, MeterValueUnit, + type OCPP16ChargePointStatus, type OCPP16StatusNotificationRequest, + type OCPP20ConnectorStatusEnumType, type OCPP20StatusNotificationRequest, OCPPVersion, RequestCommand, @@ -41,246 +43,252 @@ import { type SampledValueTemplate, StandardParametersKey, type StatusNotificationRequest, - type StatusNotificationResponse, -} from '../../types'; + type StatusNotificationResponse +} from '../../types/index.js' import { ACElectricUtils, Constants, - DCElectricUtils, convertToFloat, convertToInt, + DCElectricUtils, getRandomFloatFluctuatedRounded, getRandomFloatRounded, getRandomInteger, handleFileException, isNotEmptyArray, isNotEmptyString, - isNullOrUndefined, - isUndefined, - logPrefix, logger, + logPrefix, max, min, - roundTo, -} from '../../utils'; + roundTo +} from '../../utils/index.js' +import { OCPP16Constants } from './1.6/OCPP16Constants.js' +import { OCPP20Constants } from './2.0/OCPP20Constants.js' +import { OCPPConstants } from './OCPPConstants.js' -export const getMessageTypeString = (messageType: MessageType): string => { +export const getMessageTypeString = (messageType: MessageType | undefined): string => { switch (messageType) { case MessageType.CALL_MESSAGE: - return 'request'; + return 'request' case MessageType.CALL_RESULT_MESSAGE: - return 'response'; + return 'response' case MessageType.CALL_ERROR_MESSAGE: - return 'error'; + return 'error' default: - return 'unknown'; + return 'unknown' } -}; +} -export const buildStatusNotificationRequest = ( +const buildStatusNotificationRequest = ( chargingStation: ChargingStation, connectorId: number, status: ConnectorStatusEnum, - evseId?: number, + evseId?: number ): StatusNotificationRequest => { switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: return { connectorId, - status, - errorCode: ChargePointErrorCode.NO_ERROR, - } as OCPP16StatusNotificationRequest; + status: status as OCPP16ChargePointStatus, + errorCode: ChargePointErrorCode.NO_ERROR + } satisfies OCPP16StatusNotificationRequest case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: return { timestamp: new Date(), - connectorStatus: status, + connectorStatus: status as OCPP20ConnectorStatusEnumType, connectorId, - evseId, - } as OCPP20StatusNotificationRequest; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + evseId: evseId! + } satisfies OCPP20StatusNotificationRequest default: - throw new BaseError('Cannot build status notification payload: OCPP version not supported'); + throw new BaseError('Cannot build status notification payload: OCPP version not supported') } -}; +} export const isIdTagAuthorized = async ( chargingStation: ChargingStation, connectorId: number, - idTag: string, + idTag: string ): Promise => { if ( !chargingStation.getLocalAuthListEnabled() && - !chargingStation.stationInfo?.remoteAuthorization + chargingStation.stationInfo?.remoteAuthorization === false ) { logger.warn( - `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`, - ); + `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur` + ) } + const connectorStatus = chargingStation.getConnectorStatus(connectorId) if ( - chargingStation.getLocalAuthListEnabled() === true && + connectorStatus != null && + chargingStation.getLocalAuthListEnabled() && isIdTagLocalAuthorized(chargingStation, idTag) ) { - const connectorStatus: ConnectorStatus = chargingStation.getConnectorStatus(connectorId)!; - connectorStatus.localAuthorizeIdTag = idTag; - connectorStatus.idTagLocalAuthorized = true; - return true; - } else if (chargingStation.stationInfo?.remoteAuthorization) { - return await isIdTagRemoteAuthorized(chargingStation, connectorId, idTag); + connectorStatus.localAuthorizeIdTag = idTag + connectorStatus.idTagLocalAuthorized = true + return true + } else if (chargingStation.stationInfo?.remoteAuthorization === true) { + return await isIdTagRemoteAuthorized(chargingStation, connectorId, idTag) } - return false; -}; + return false +} const isIdTagLocalAuthorized = (chargingStation: ChargingStation, idTag: string): boolean => { return ( - chargingStation.hasIdTags() === true && + chargingStation.hasIdTags() && isNotEmptyString( chargingStation.idTagsCache - .getIdTags(getIdTagsFile(chargingStation.stationInfo)!) - ?.find((tag) => tag === idTag), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .getIdTags(getIdTagsFile(chargingStation.stationInfo!)!) + ?.find(tag => tag === idTag) ) - ); -}; + ) +} const isIdTagRemoteAuthorized = async ( chargingStation: ChargingStation, connectorId: number, - idTag: string, + idTag: string ): Promise => { - chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag return ( ( await chargingStation.ocppRequestService.requestHandler( chargingStation, RequestCommand.AUTHORIZE, { - idTag, - }, + idTag + } ) - )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED - ); -}; + ).idTagInfo.status === AuthorizationStatus.ACCEPTED + ) +} export const sendAndSetConnectorStatus = async ( chargingStation: ChargingStation, connectorId: number, status: ConnectorStatusEnum, evseId?: number, - options?: { send: boolean }, + options?: { send: boolean } ): Promise => { - options = { send: true, ...options }; + options = { send: true, ...options } if (options.send) { - checkConnectorStatusTransition(chargingStation, connectorId, status); + checkConnectorStatusTransition(chargingStation, connectorId, status) await chargingStation.ocppRequestService.requestHandler< - StatusNotificationRequest, - StatusNotificationResponse + StatusNotificationRequest, + StatusNotificationResponse >( chargingStation, RequestCommand.STATUS_NOTIFICATION, - buildStatusNotificationRequest(chargingStation, connectorId, status, evseId), - ); + buildStatusNotificationRequest(chargingStation, connectorId, status, evseId) + ) } - chargingStation.getConnectorStatus(connectorId)!.status = status; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.getConnectorStatus(connectorId)!.status = status chargingStation.emit(ChargingStationEvents.connectorStatusChanged, { connectorId, - ...chargingStation.getConnectorStatus(connectorId), - }); -}; + ...chargingStation.getConnectorStatus(connectorId) + }) +} const checkConnectorStatusTransition = ( chargingStation: ChargingStation, connectorId: number, - status: ConnectorStatusEnum, + status: ConnectorStatusEnum ): boolean => { - const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status; - let transitionAllowed = false; + const fromStatus = chargingStation.getConnectorStatus(connectorId)?.status + let transitionAllowed = false switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: if ( (connectorId === 0 && OCPP16Constants.ChargePointStatusChargingStationTransitions.findIndex( - (transition) => transition.from === fromStatus && transition.to === status, + transition => transition.from === fromStatus && transition.to === status ) !== -1) || (connectorId > 0 && OCPP16Constants.ChargePointStatusConnectorTransitions.findIndex( - (transition) => transition.from === fromStatus && transition.to === status, + transition => transition.from === fromStatus && transition.to === status ) !== -1) ) { - transitionAllowed = true; + transitionAllowed = true } - break; + break case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: if ( (connectorId === 0 && OCPP20Constants.ChargingStationStatusTransitions.findIndex( - (transition) => transition.from === fromStatus && transition.to === status, + transition => transition.from === fromStatus && transition.to === status ) !== -1) || (connectorId > 0 && OCPP20Constants.ConnectorStatusTransitions.findIndex( - (transition) => transition.from === fromStatus && transition.to === status, + transition => transition.from === fromStatus && transition.to === status ) !== -1) ) { - transitionAllowed = true; + transitionAllowed = true } - break; + break default: throw new BaseError( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`, - ); + `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported` + ) } - if (transitionAllowed === false) { + if (!transitionAllowed) { logger.warn( - `${chargingStation.logPrefix()} OCPP ${chargingStation.stationInfo - ?.ocppVersion} connector id ${connectorId} status transition from '${ - chargingStation.getConnectorStatus(connectorId)!.status - }' to '${status}' is not allowed`, - ); + `${chargingStation.logPrefix()} OCPP ${ + chargingStation.stationInfo.ocppVersion + } connector id ${connectorId} status transition from '${ + chargingStation.getConnectorStatus(connectorId)?.status + }' to '${status}' is not allowed` + ) } - return transitionAllowed; -}; + return transitionAllowed +} export const buildMeterValue = ( chargingStation: ChargingStation, connectorId: number, transactionId: number, interval: number, - debug = false, + debug = false ): MeterValue => { - const connector = chargingStation.getConnectorStatus(connectorId); - let meterValue: MeterValue; - let socSampledValueTemplate: SampledValueTemplate | undefined; - let voltageSampledValueTemplate: SampledValueTemplate | undefined; - let powerSampledValueTemplate: SampledValueTemplate | undefined; - let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {}; - let currentSampledValueTemplate: SampledValueTemplate | undefined; - let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {}; - let energySampledValueTemplate: SampledValueTemplate | undefined; + const connector = chargingStation.getConnectorStatus(connectorId) + let meterValue: MeterValue + let socSampledValueTemplate: SampledValueTemplate | undefined + let voltageSampledValueTemplate: SampledValueTemplate | undefined + let powerSampledValueTemplate: SampledValueTemplate | undefined + let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {} + let currentSampledValueTemplate: SampledValueTemplate | undefined + let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {} + let energySampledValueTemplate: SampledValueTemplate | undefined switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: meterValue = { timestamp: new Date(), - sampledValue: [], - }; + sampledValue: [] + } // SoC measurand socSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, - MeterValueMeasurand.STATE_OF_CHARGE, - ); - if (socSampledValueTemplate) { - const socMaximumValue = 100; - const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0; + MeterValueMeasurand.STATE_OF_CHARGE + ) + if (socSampledValueTemplate != null) { + const socMaximumValue = 100 + const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0 const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value) ? getRandomFloatFluctuatedRounded( - parseInt(socSampledValueTemplate.value), - socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : getRandomInteger(socMaximumValue, socMinimumValue); + parseInt(socSampledValueTemplate.value), + socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : getRandomInteger(socMaximumValue, socMinimumValue) meterValue.sampledValue.push( - buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue), - ); - const sampledValuesIndex = meterValue.sampledValue.length - 1; + buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue) + ) + const sampledValuesIndex = meterValue.sampledValue.length - 1 if ( convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > socMaximumValue || convertToInt(meterValue.sampledValue[sampledValuesIndex].value) < socMinimumValue || @@ -292,114 +300,117 @@ export const buildMeterValue = ( MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${socMinimumValue}/${ meterValue.sampledValue[sampledValuesIndex].value - }/${socMaximumValue}`, - ); + }/${socMaximumValue}` + ) } } // Voltage measurand voltageSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, - MeterValueMeasurand.VOLTAGE, - ); - if (voltageSampledValueTemplate) { + MeterValueMeasurand.VOLTAGE + ) + if (voltageSampledValueTemplate != null) { const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value) ? parseInt(voltageSampledValueTemplate.value) - : chargingStation.stationInfo.voltageOut!; + : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.stationInfo.voltageOut! const fluctuationPercent = - voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT; + voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT const voltageMeasurandValue = getRandomFloatFluctuatedRounded( voltageSampledValueTemplateValue, - fluctuationPercent, - ); + fluctuationPercent + ) if ( chargingStation.getNumberOfPhases() !== 3 || (chargingStation.getNumberOfPhases() === 3 && - chargingStation.stationInfo?.mainVoltageMeterValues) + chargingStation.stationInfo.mainVoltageMeterValues === true) ) { meterValue.sampledValue.push( - buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue), - ); + buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue) + ) } for ( let phase = 1; chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases(); phase++ ) { - const phaseLineToNeutralValue = `L${phase}-N`; + const phaseLineToNeutralValue = `L${phase}-N` const voltagePhaseLineToNeutralSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.VOLTAGE, - phaseLineToNeutralValue as MeterValuePhase, - ); - let voltagePhaseLineToNeutralMeasurandValue: number | undefined; - if (voltagePhaseLineToNeutralSampledValueTemplate) { + phaseLineToNeutralValue as MeterValuePhase + ) + let voltagePhaseLineToNeutralMeasurandValue: number | undefined + if (voltagePhaseLineToNeutralSampledValueTemplate != null) { const voltagePhaseLineToNeutralSampledValueTemplateValue = isNotEmptyString( - voltagePhaseLineToNeutralSampledValueTemplate.value, + voltagePhaseLineToNeutralSampledValueTemplate.value ) ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value) - : chargingStation.stationInfo.voltageOut!; + : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.stationInfo.voltageOut! const fluctuationPhaseToNeutralPercent = voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT; + Constants.DEFAULT_FLUCTUATION_PERCENT voltagePhaseLineToNeutralMeasurandValue = getRandomFloatFluctuatedRounded( voltagePhaseLineToNeutralSampledValueTemplateValue, - fluctuationPhaseToNeutralPercent, - ); + fluctuationPhaseToNeutralPercent + ) } meterValue.sampledValue.push( buildSampledValue( voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate, voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue, undefined, - phaseLineToNeutralValue as MeterValuePhase, - ), - ); - if (chargingStation.stationInfo?.phaseLineToLineVoltageMeterValues) { + phaseLineToNeutralValue as MeterValuePhase + ) + ) + if (chargingStation.stationInfo.phaseLineToLineVoltageMeterValues === true) { const phaseLineToLineValue = `L${phase}-L${ (phase + 1) % chargingStation.getNumberOfPhases() !== 0 ? (phase + 1) % chargingStation.getNumberOfPhases() : chargingStation.getNumberOfPhases() - }`; + }` const voltagePhaseLineToLineValueRounded = roundTo( Math.sqrt(chargingStation.getNumberOfPhases()) * + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion chargingStation.stationInfo.voltageOut!, - 2, - ); + 2 + ) const voltagePhaseLineToLineSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.VOLTAGE, - phaseLineToLineValue as MeterValuePhase, - ); - let voltagePhaseLineToLineMeasurandValue: number | undefined; - if (voltagePhaseLineToLineSampledValueTemplate) { + phaseLineToLineValue as MeterValuePhase + ) + let voltagePhaseLineToLineMeasurandValue: number | undefined + if (voltagePhaseLineToLineSampledValueTemplate != null) { const voltagePhaseLineToLineSampledValueTemplateValue = isNotEmptyString( - voltagePhaseLineToLineSampledValueTemplate.value, + voltagePhaseLineToLineSampledValueTemplate.value ) ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value) - : voltagePhaseLineToLineValueRounded; + : voltagePhaseLineToLineValueRounded const fluctuationPhaseLineToLinePercent = voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT; + Constants.DEFAULT_FLUCTUATION_PERCENT voltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded( voltagePhaseLineToLineSampledValueTemplateValue, - fluctuationPhaseLineToLinePercent, - ); + fluctuationPhaseLineToLinePercent + ) } const defaultVoltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded( voltagePhaseLineToLineValueRounded, - fluctuationPercent, - ); + fluctuationPercent + ) meterValue.sampledValue.push( buildSampledValue( voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate, voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue, undefined, - phaseLineToLineValue as MeterValuePhase, - ), - ); + phaseLineToLineValue as MeterValuePhase + ) + ) } } } @@ -407,206 +418,207 @@ export const buildMeterValue = ( powerSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, - MeterValueMeasurand.POWER_ACTIVE_IMPORT, - ); + MeterValueMeasurand.POWER_ACTIVE_IMPORT + ) if (chargingStation.getNumberOfPhases() === 3) { powerPerPhaseSampledValueTemplates = { L1: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.POWER_ACTIVE_IMPORT, - MeterValuePhase.L1_N, + MeterValuePhase.L1_N ), L2: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.POWER_ACTIVE_IMPORT, - MeterValuePhase.L2_N, + MeterValuePhase.L2_N ), L3: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.POWER_ACTIVE_IMPORT, - MeterValuePhase.L3_N, - ), - }; + MeterValuePhase.L3_N + ) + } } - if (powerSampledValueTemplate) { - checkMeasurandPowerDivider(chargingStation, powerSampledValueTemplate.measurand!); + if (powerSampledValueTemplate != null) { + checkMeasurandPowerDivider(chargingStation, powerSampledValueTemplate.measurand) const errMsg = `MeterValues measurand ${ powerSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${ + }: Unknown ${chargingStation.stationInfo.currentOutType} currentOutType in template file ${ chargingStation.templateFile }, cannot calculate ${ powerSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - } measurand value`; - const powerMeasurandValues: MeasurandValues = {} as MeasurandValues; - const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1; + } measurand value` + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const powerMeasurandValues: MeasurandValues = {} as MeasurandValues + const unitDivider = powerSampledValueTemplate.unit === MeterValueUnit.KILO_WATT ? 1000 : 1 const connectorMaximumAvailablePower = - chargingStation.getConnectorMaximumAvailablePower(connectorId); - const connectorMaximumPower = Math.round(connectorMaximumAvailablePower); + chargingStation.getConnectorMaximumAvailablePower(connectorId) + const connectorMaximumPower = Math.round(connectorMaximumAvailablePower) const connectorMaximumPowerPerPhase = Math.round( - connectorMaximumAvailablePower / chargingStation.getNumberOfPhases(), - ); - const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue ?? 0); + connectorMaximumAvailablePower / chargingStation.getNumberOfPhases() + ) + const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue ?? 0) const connectorMinimumPowerPerPhase = Math.round( - connectorMinimumPower / chargingStation.getNumberOfPhases(), - ); - switch (chargingStation.stationInfo?.currentOutType) { + connectorMinimumPower / chargingStation.getNumberOfPhases() + ) + switch (chargingStation.stationInfo.currentOutType) { case CurrentType.AC: if (chargingStation.getNumberOfPhases() === 3) { const defaultFluctuatedPowerPerPhase = isNotEmptyString( - powerSampledValueTemplate.value, + powerSampledValueTemplate.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - powerSampledValueTemplate.value, - connectorMaximumPower / unitDivider, - connectorMinimumPower / unitDivider, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPower / unitDivider, - }, - ) / chargingStation.getNumberOfPhases(), - powerSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + powerSampledValueTemplate.value, + connectorMaximumPower / unitDivider, + connectorMinimumPower / unitDivider, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPower / unitDivider + } + ) / chargingStation.getNumberOfPhases(), + powerSampledValueTemplate.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase1FluctuatedValue = isNotEmptyString( - powerPerPhaseSampledValueTemplates.L1?.value, + powerPerPhaseSampledValueTemplates.L1?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - powerPerPhaseSampledValueTemplates.L1?.value, - connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPowerPerPhase / unitDivider, - }, - ), - powerPerPhaseSampledValueTemplates.L1?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + powerPerPhaseSampledValueTemplates.L1.value, + connectorMaximumPowerPerPhase / unitDivider, + connectorMinimumPowerPerPhase / unitDivider, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPowerPerPhase / unitDivider + } + ), + powerPerPhaseSampledValueTemplates.L1.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase2FluctuatedValue = isNotEmptyString( - powerPerPhaseSampledValueTemplates.L2?.value, + powerPerPhaseSampledValueTemplates.L2?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - powerPerPhaseSampledValueTemplates.L2?.value, - connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPowerPerPhase / unitDivider, - }, - ), - powerPerPhaseSampledValueTemplates.L2?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + powerPerPhaseSampledValueTemplates.L2.value, + connectorMaximumPowerPerPhase / unitDivider, + connectorMinimumPowerPerPhase / unitDivider, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPowerPerPhase / unitDivider + } + ), + powerPerPhaseSampledValueTemplates.L2.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase3FluctuatedValue = isNotEmptyString( - powerPerPhaseSampledValueTemplates.L3?.value, + powerPerPhaseSampledValueTemplates.L3?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - powerPerPhaseSampledValueTemplates.L3?.value, - connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPowerPerPhase / unitDivider, - }, - ), - powerPerPhaseSampledValueTemplates.L3?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + powerPerPhaseSampledValueTemplates.L3.value, + connectorMaximumPowerPerPhase / unitDivider, + connectorMinimumPowerPerPhase / unitDivider, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPowerPerPhase / unitDivider + } + ), + powerPerPhaseSampledValueTemplates.L3.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined powerMeasurandValues.L1 = phase1FluctuatedValue ?? defaultFluctuatedPowerPerPhase ?? getRandomFloatRounded( connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - ); + connectorMinimumPowerPerPhase / unitDivider + ) powerMeasurandValues.L2 = phase2FluctuatedValue ?? defaultFluctuatedPowerPerPhase ?? getRandomFloatRounded( connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - ); + connectorMinimumPowerPerPhase / unitDivider + ) powerMeasurandValues.L3 = phase3FluctuatedValue ?? defaultFluctuatedPowerPerPhase ?? getRandomFloatRounded( connectorMaximumPowerPerPhase / unitDivider, - connectorMinimumPowerPerPhase / unitDivider, - ); + connectorMinimumPowerPerPhase / unitDivider + ) } else { powerMeasurandValues.L1 = isNotEmptyString(powerSampledValueTemplate.value) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - powerSampledValueTemplate.value, - connectorMaximumPower / unitDivider, - connectorMinimumPower / unitDivider, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPower / unitDivider, - }, - ), - powerSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : getRandomFloatRounded( - connectorMaximumPower / unitDivider, - connectorMinimumPower / unitDivider, - ); - powerMeasurandValues.L2 = 0; - powerMeasurandValues.L3 = 0; - } - powerMeasurandValues.allPhases = roundTo( - powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, - 2, - ); - break; - case CurrentType.DC: - powerMeasurandValues.allPhases = isNotEmptyString(powerSampledValueTemplate.value) - ? getRandomFloatFluctuatedRounded( getLimitFromSampledValueTemplateCustomValue( powerSampledValueTemplate.value, connectorMaximumPower / unitDivider, connectorMinimumPower / unitDivider, { limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumPower / unitDivider, - }, + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPower / unitDivider + } ), powerSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, + Constants.DEFAULT_FLUCTUATION_PERCENT ) - : getRandomFloatRounded( + : getRandomFloatRounded( + connectorMaximumPower / unitDivider, + connectorMinimumPower / unitDivider + ) + powerMeasurandValues.L2 = 0 + powerMeasurandValues.L3 = 0 + } + powerMeasurandValues.allPhases = roundTo( + powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, + 2 + ) + break + case CurrentType.DC: + powerMeasurandValues.allPhases = isNotEmptyString(powerSampledValueTemplate.value) + ? getRandomFloatFluctuatedRounded( + getLimitFromSampledValueTemplateCustomValue( + powerSampledValueTemplate.value, connectorMaximumPower / unitDivider, connectorMinimumPower / unitDivider, - ); - break; + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumPower / unitDivider + } + ), + powerSampledValueTemplate.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : getRandomFloatRounded( + connectorMaximumPower / unitDivider, + connectorMinimumPower / unitDivider + ) + break default: - logger.error(`${chargingStation.logPrefix()} ${errMsg}`); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); + logger.error(`${chargingStation.logPrefix()} ${errMsg}`) + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES) } meterValue.sampledValue.push( - buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases), - ); - const sampledValuesIndex = meterValue.sampledValue.length - 1; - const connectorMaximumPowerRounded = roundTo(connectorMaximumPower / unitDivider, 2); - const connectorMinimumPowerRounded = roundTo(connectorMinimumPower / unitDivider, 2); + buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases) + ) + const sampledValuesIndex = meterValue.sampledValue.length - 1 + const connectorMaximumPowerRounded = roundTo(connectorMaximumPower / unitDivider, 2) + const connectorMinimumPowerRounded = roundTo(connectorMinimumPower / unitDivider, 2) if ( convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > connectorMaximumPowerRounded || @@ -620,15 +632,15 @@ export const buildMeterValue = ( MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerRounded}/${ meterValue.sampledValue[sampledValuesIndex].value - }/${connectorMaximumPowerRounded}`, - ); + }/${connectorMaximumPowerRounded}` + ) } for ( let phase = 1; chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases(); phase++ ) { - const phaseValue = `L${phase}-N`; + const phaseValue = `L${phase}-N` meterValue.sampledValue.push( buildSampledValue( powerPerPhaseSampledValueTemplates[ @@ -636,18 +648,18 @@ export const buildMeterValue = ( ] ?? powerSampledValueTemplate, powerMeasurandValues[`L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates], undefined, - phaseValue as MeterValuePhase, - ), - ); - const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1; + phaseValue as MeterValuePhase + ) + ) + const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1 const connectorMaximumPowerPerPhaseRounded = roundTo( connectorMaximumPowerPerPhase / unitDivider, - 2, - ); + 2 + ) const connectorMinimumPowerPerPhaseRounded = roundTo( connectorMinimumPowerPerPhase / unitDivider, - 2, - ); + 2 + ) if ( convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > connectorMaximumPowerPerPhaseRounded || @@ -663,8 +675,8 @@ export const buildMeterValue = ( meterValue.sampledValue[sampledValuesPerPhaseIndex].phase }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerPerPhaseRounded}/${ meterValue.sampledValue[sampledValuesPerPhaseIndex].value - }/${connectorMaximumPowerPerPhaseRounded}`, - ); + }/${connectorMaximumPowerPerPhaseRounded}` + ) } } } @@ -672,192 +684,196 @@ export const buildMeterValue = ( currentSampledValueTemplate = getSampledValueTemplate( chargingStation, connectorId, - MeterValueMeasurand.CURRENT_IMPORT, - ); + MeterValueMeasurand.CURRENT_IMPORT + ) if (chargingStation.getNumberOfPhases() === 3) { currentPerPhaseSampledValueTemplates = { L1: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.CURRENT_IMPORT, - MeterValuePhase.L1, + MeterValuePhase.L1 ), L2: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.CURRENT_IMPORT, - MeterValuePhase.L2, + MeterValuePhase.L2 ), L3: getSampledValueTemplate( chargingStation, connectorId, MeterValueMeasurand.CURRENT_IMPORT, - MeterValuePhase.L3, - ), - }; + MeterValuePhase.L3 + ) + } } - if (currentSampledValueTemplate) { - checkMeasurandPowerDivider(chargingStation, currentSampledValueTemplate.measurand!); + if (currentSampledValueTemplate != null) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + checkMeasurandPowerDivider(chargingStation, currentSampledValueTemplate.measurand) const errMsg = `MeterValues measurand ${ currentSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${ + }: Unknown ${chargingStation.stationInfo.currentOutType} currentOutType in template file ${ chargingStation.templateFile }, cannot calculate ${ currentSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - } measurand value`; - const currentMeasurandValues: MeasurandValues = {} as MeasurandValues; + } measurand value` + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const currentMeasurandValues: MeasurandValues = {} as MeasurandValues const connectorMaximumAvailablePower = - chargingStation.getConnectorMaximumAvailablePower(connectorId); - const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0; - let connectorMaximumAmperage: number; - switch (chargingStation.stationInfo?.currentOutType) { + chargingStation.getConnectorMaximumAvailablePower(connectorId) + const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0 + let connectorMaximumAmperage: number + switch (chargingStation.stationInfo.currentOutType) { case CurrentType.AC: connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower( chargingStation.getNumberOfPhases(), connectorMaximumAvailablePower, - chargingStation.stationInfo.voltageOut!, - ); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.stationInfo.voltageOut! + ) if (chargingStation.getNumberOfPhases() === 3) { const defaultFluctuatedAmperagePerPhase = isNotEmptyString( - currentSampledValueTemplate.value, + currentSampledValueTemplate.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - currentSampledValueTemplate.value, - connectorMaximumAmperage, - connectorMinimumAmperage, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, - ), - currentSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + currentSampledValueTemplate.value, + connectorMaximumAmperage, + connectorMinimumAmperage, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } + ), + currentSampledValueTemplate.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase1FluctuatedValue = isNotEmptyString( - currentPerPhaseSampledValueTemplates.L1?.value, + currentPerPhaseSampledValueTemplates.L1?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - currentPerPhaseSampledValueTemplates.L1?.value, - connectorMaximumAmperage, - connectorMinimumAmperage, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, - ), - currentPerPhaseSampledValueTemplates.L1?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + currentPerPhaseSampledValueTemplates.L1.value, + connectorMaximumAmperage, + connectorMinimumAmperage, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } + ), + currentPerPhaseSampledValueTemplates.L1.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase2FluctuatedValue = isNotEmptyString( - currentPerPhaseSampledValueTemplates.L2?.value, + currentPerPhaseSampledValueTemplates.L2?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - currentPerPhaseSampledValueTemplates.L2?.value, - connectorMaximumAmperage, - connectorMinimumAmperage, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, - ), - currentPerPhaseSampledValueTemplates.L2?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + currentPerPhaseSampledValueTemplates.L2.value, + connectorMaximumAmperage, + connectorMinimumAmperage, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } + ), + currentPerPhaseSampledValueTemplates.L2.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined const phase3FluctuatedValue = isNotEmptyString( - currentPerPhaseSampledValueTemplates.L3?.value, + currentPerPhaseSampledValueTemplates.L3?.value ) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - currentPerPhaseSampledValueTemplates.L3?.value, - connectorMaximumAmperage, - connectorMinimumAmperage, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, - ), - currentPerPhaseSampledValueTemplates.L3?.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : undefined; + getLimitFromSampledValueTemplateCustomValue( + currentPerPhaseSampledValueTemplates.L3.value, + connectorMaximumAmperage, + connectorMinimumAmperage, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } + ), + currentPerPhaseSampledValueTemplates.L3.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : undefined currentMeasurandValues.L1 = phase1FluctuatedValue ?? defaultFluctuatedAmperagePerPhase ?? - getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage); + getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage) currentMeasurandValues.L2 = phase2FluctuatedValue ?? defaultFluctuatedAmperagePerPhase ?? - getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage); + getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage) currentMeasurandValues.L3 = phase3FluctuatedValue ?? defaultFluctuatedAmperagePerPhase ?? - getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage); + getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage) } else { currentMeasurandValues.L1 = isNotEmptyString(currentSampledValueTemplate.value) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - currentSampledValueTemplate.value, - connectorMaximumAmperage, - connectorMinimumAmperage, - { - limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, - ), - currentSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage); - currentMeasurandValues.L2 = 0; - currentMeasurandValues.L3 = 0; - } - currentMeasurandValues.allPhases = roundTo( - (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / - chargingStation.getNumberOfPhases(), - 2, - ); - break; - case CurrentType.DC: - connectorMaximumAmperage = DCElectricUtils.amperage( - connectorMaximumAvailablePower, - chargingStation.stationInfo.voltageOut!, - ); - currentMeasurandValues.allPhases = isNotEmptyString(currentSampledValueTemplate.value) - ? getRandomFloatFluctuatedRounded( getLimitFromSampledValueTemplateCustomValue( currentSampledValueTemplate.value, connectorMaximumAmperage, connectorMinimumAmperage, { limitationEnabled: - chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumAmperage, - }, + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } ), currentSampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, + Constants.DEFAULT_FLUCTUATION_PERCENT ) - : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage); - break; + : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage) + currentMeasurandValues.L2 = 0 + currentMeasurandValues.L3 = 0 + } + currentMeasurandValues.allPhases = roundTo( + (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / + chargingStation.getNumberOfPhases(), + 2 + ) + break + case CurrentType.DC: + connectorMaximumAmperage = DCElectricUtils.amperage( + connectorMaximumAvailablePower, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.stationInfo.voltageOut! + ) + currentMeasurandValues.allPhases = isNotEmptyString(currentSampledValueTemplate.value) + ? getRandomFloatFluctuatedRounded( + getLimitFromSampledValueTemplateCustomValue( + currentSampledValueTemplate.value, + connectorMaximumAmperage, + connectorMinimumAmperage, + { + limitationEnabled: + chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumAmperage + } + ), + currentSampledValueTemplate.fluctuationPercent ?? + Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage) + break default: - logger.error(`${chargingStation.logPrefix()} ${errMsg}`); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); + logger.error(`${chargingStation.logPrefix()} ${errMsg}`) + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES) } meterValue.sampledValue.push( - buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases), - ); - const sampledValuesIndex = meterValue.sampledValue.length - 1; + buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases) + ) + const sampledValuesIndex = meterValue.sampledValue.length - 1 if ( convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > connectorMaximumAmperage || @@ -871,15 +887,15 @@ export const buildMeterValue = ( MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${ meterValue.sampledValue[sampledValuesIndex].value - }/${connectorMaximumAmperage}`, - ); + }/${connectorMaximumAmperage}` + ) } for ( let phase = 1; chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases(); phase++ ) { - const phaseValue = `L${phase}`; + const phaseValue = `L${phase}` meterValue.sampledValue.push( buildSampledValue( currentPerPhaseSampledValueTemplates[ @@ -887,10 +903,10 @@ export const buildMeterValue = ( ] ?? currentSampledValueTemplate, currentMeasurandValues[phaseValue as keyof MeasurandPerPhaseSampledValueTemplates], undefined, - phaseValue as MeterValuePhase, - ), - ); - const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1; + phaseValue as MeterValuePhase + ) + ) + const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1 if ( convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > connectorMaximumAmperage || @@ -906,56 +922,55 @@ export const buildMeterValue = ( meterValue.sampledValue[sampledValuesPerPhaseIndex].phase }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${ meterValue.sampledValue[sampledValuesPerPhaseIndex].value - }/${connectorMaximumAmperage}`, - ); + }/${connectorMaximumAmperage}` + ) } } } // Energy.Active.Import.Register measurand (default) - energySampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId); - if (energySampledValueTemplate) { - checkMeasurandPowerDivider(chargingStation, energySampledValueTemplate.measurand!); + energySampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId) + if (energySampledValueTemplate != null) { + checkMeasurandPowerDivider(chargingStation, energySampledValueTemplate.measurand) const unitDivider = - energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1; + energySampledValueTemplate.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1 const connectorMaximumAvailablePower = - chargingStation.getConnectorMaximumAvailablePower(connectorId); + chargingStation.getConnectorMaximumAvailablePower(connectorId) const connectorMaximumEnergyRounded = roundTo( (connectorMaximumAvailablePower * interval) / (3600 * 1000), - 2, - ); + 2 + ) const connectorMinimumEnergyRounded = roundTo( energySampledValueTemplate.minimumValue ?? 0, - 2, - ); + 2 + ) const energyValueRounded = isNotEmptyString(energySampledValueTemplate.value) ? getRandomFloatFluctuatedRounded( - getLimitFromSampledValueTemplateCustomValue( - energySampledValueTemplate.value, - connectorMaximumEnergyRounded, - connectorMinimumEnergyRounded, - { - limitationEnabled: chargingStation.stationInfo?.customValueLimitationMeterValues, - fallbackValue: connectorMinimumEnergyRounded, - unitMultiplier: unitDivider, - }, - ), - energySampledValueTemplate.fluctuationPercent ?? - Constants.DEFAULT_FLUCTUATION_PERCENT, - ) - : getRandomFloatRounded(connectorMaximumEnergyRounded, connectorMinimumEnergyRounded); + getLimitFromSampledValueTemplateCustomValue( + energySampledValueTemplate.value, + connectorMaximumEnergyRounded, + connectorMinimumEnergyRounded, + { + limitationEnabled: chargingStation.stationInfo.customValueLimitationMeterValues, + fallbackValue: connectorMinimumEnergyRounded, + unitMultiplier: unitDivider + } + ), + energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT + ) + : getRandomFloatRounded(connectorMaximumEnergyRounded, connectorMinimumEnergyRounded) // Persist previous value on connector - if (connector) { + if (connector != null) { if ( - isNullOrUndefined(connector.energyActiveImportRegisterValue) === false && - connector.energyActiveImportRegisterValue! >= 0 && - isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false && - connector.transactionEnergyActiveImportRegisterValue! >= 0 + connector.energyActiveImportRegisterValue != null && + connector.energyActiveImportRegisterValue >= 0 && + connector.transactionEnergyActiveImportRegisterValue != null && + connector.transactionEnergyActiveImportRegisterValue >= 0 ) { - connector.energyActiveImportRegisterValue! += energyValueRounded; - connector.transactionEnergyActiveImportRegisterValue! += energyValueRounded; + connector.energyActiveImportRegisterValue += energyValueRounded + connector.transactionEnergyActiveImportRegisterValue += energyValueRounded } else { - connector.energyActiveImportRegisterValue = 0; - connector.transactionEnergyActiveImportRegisterValue = 0; + connector.energyActiveImportRegisterValue = 0 + connector.transactionEnergyActiveImportRegisterValue = 0 } } meterValue.sampledValue.push( @@ -964,11 +979,11 @@ export const buildMeterValue = ( roundTo( chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) / unitDivider, - 2, - ), - ), - ); - const sampledValuesIndex = meterValue.sampledValue.length - 1; + 2 + ) + ) + ) + const sampledValuesIndex = meterValue.sampledValue.length - 1 if ( energyValueRounded > connectorMaximumEnergyRounded || energyValueRounded < connectorMinimumEnergyRounded || @@ -978,358 +993,361 @@ export const buildMeterValue = ( `${chargingStation.logPrefix()} MeterValues measurand ${ meterValue.sampledValue[sampledValuesIndex].measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumEnergyRounded}/${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms`, - ); + }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumEnergyRounded}/${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms` + ) } } - return meterValue; + return meterValue case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: default: throw new BaseError( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`, - ); + `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported` + ) } -}; +} export const buildTransactionEndMeterValue = ( chargingStation: ChargingStation, connectorId: number, - meterStop: number, + meterStop: number | undefined ): MeterValue => { - let meterValue: MeterValue; - let sampledValueTemplate: SampledValueTemplate | undefined; - let unitDivider: number; + let meterValue: MeterValue + let sampledValueTemplate: SampledValueTemplate | undefined + let unitDivider: number switch (chargingStation.stationInfo?.ocppVersion) { case OCPPVersion.VERSION_16: meterValue = { timestamp: new Date(), - sampledValue: [], - }; + sampledValue: [] + } // Energy.Active.Import.Register measurand (default) - sampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId); - unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1; + sampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId) + unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1 meterValue.sampledValue.push( buildSampledValue( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion sampledValueTemplate!, roundTo((meterStop ?? 0) / unitDivider, 4), - MeterValueContext.TRANSACTION_END, - ), - ); - return meterValue; + MeterValueContext.TRANSACTION_END + ) + ) + return meterValue case OCPPVersion.VERSION_20: case OCPPVersion.VERSION_201: default: throw new BaseError( - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`, - ); + `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported` + ) } -}; +} const checkMeasurandPowerDivider = ( chargingStation: ChargingStation, - measurandType: MeterValueMeasurand, + measurandType: MeterValueMeasurand | undefined ): void => { - if (isUndefined(chargingStation.powerDivider)) { + if (chargingStation.powerDivider == null) { const errMsg = `MeterValues measurand ${ measurandType ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: powerDivider is undefined`; - logger.error(`${chargingStation.logPrefix()} ${errMsg}`); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); - } else if (chargingStation?.powerDivider <= 0) { + }: powerDivider is undefined` + logger.error(`${chargingStation.logPrefix()} ${errMsg}`) + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES) + } else if (chargingStation.powerDivider <= 0) { const errMsg = `MeterValues measurand ${ measurandType ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: powerDivider have zero or below value ${chargingStation.powerDivider}`; - logger.error(`${chargingStation.logPrefix()} ${errMsg}`); - throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES); + }: powerDivider have zero or below value ${chargingStation.powerDivider}` + logger.error(`${chargingStation.logPrefix()} ${errMsg}`) + throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES) } -}; +} const getLimitFromSampledValueTemplateCustomValue = ( value: string | undefined, maxLimit: number, minLimit: number, - options?: { limitationEnabled?: boolean; fallbackValue?: number; unitMultiplier?: number }, + options?: { limitationEnabled?: boolean, fallbackValue?: number, unitMultiplier?: number } ): number => { options = { ...{ limitationEnabled: false, unitMultiplier: 1, - fallbackValue: 0, + fallbackValue: 0 }, - ...options, - }; - const parsedValue = parseInt(value ?? ''); - if (options?.limitationEnabled) { + ...options + } + const parsedValue = parseInt(value ?? '') + if (options.limitationEnabled === true) { return max( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion min((!isNaN(parsedValue) ? parsedValue : Infinity) * options.unitMultiplier!, maxLimit), - minLimit, - ); + minLimit + ) } - return (!isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier!; -}; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return (!isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier! +} const getSampledValueTemplate = ( chargingStation: ChargingStation, connectorId: number, measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER, - phase?: MeterValuePhase, + phase?: MeterValuePhase ): SampledValueTemplate | undefined => { - const onPhaseStr = phase ? `on phase ${phase} ` : ''; - if (OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(measurand) === false) { + const onPhaseStr = phase != null ? `on phase ${phase} ` : '' + if (!OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(measurand)) { logger.warn( - `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`, - ); - return; + `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}` + ) + return } if ( measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && getConfigurationKey( chargingStation, - StandardParametersKey.MeterValuesSampledData, + StandardParametersKey.MeterValuesSampledData )?.value?.includes(measurand) === false ) { logger.debug( `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId} not found in '${ StandardParametersKey.MeterValuesSampledData - }' OCPP parameter`, - ); - return; + }' OCPP parameter` + ) + return } - const sampledValueTemplates: SampledValueTemplate[] = - chargingStation.getConnectorStatus(connectorId)!.MeterValues; + const sampledValueTemplates = + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.getConnectorStatus(connectorId)!.MeterValues for ( let index = 0; - isNotEmptyArray(sampledValueTemplates) === true && index < sampledValueTemplates.length; + isNotEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length; index++ ) { if ( - OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes( - sampledValueTemplates[index]?.measurand ?? - MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER, - ) === false + !OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes( + sampledValueTemplates[index]?.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER + ) ) { logger.warn( - `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`, - ); + `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}` + ) } else if ( - phase && + phase != null && sampledValueTemplates[index]?.phase === phase && sampledValueTemplates[index]?.measurand === measurand && getConfigurationKey( chargingStation, - StandardParametersKey.MeterValuesSampledData, + StandardParametersKey.MeterValuesSampledData )?.value?.includes(measurand) === true ) { - return sampledValueTemplates[index]; + return sampledValueTemplates[index] } else if ( - !phase && - !sampledValueTemplates[index]?.phase && + phase == null && + sampledValueTemplates[index]?.phase == null && sampledValueTemplates[index]?.measurand === measurand && getConfigurationKey( chargingStation, - StandardParametersKey.MeterValuesSampledData, + StandardParametersKey.MeterValuesSampledData )?.value?.includes(measurand) === true ) { - return sampledValueTemplates[index]; + return sampledValueTemplates[index] } else if ( measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - (!sampledValueTemplates[index]?.measurand || + (sampledValueTemplates[index]?.measurand == null || sampledValueTemplates[index]?.measurand === measurand) ) { - return sampledValueTemplates[index]; + return sampledValueTemplates[index] } } if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connector id ${connectorId}`; - logger.error(`${chargingStation.logPrefix()} ${errorMsg}`); - throw new BaseError(errorMsg); + const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connector id ${connectorId}` + logger.error(`${chargingStation.logPrefix()} ${errorMsg}`) + throw new BaseError(errorMsg) } logger.debug( - `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`, - ); -}; + `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}` + ) +} const buildSampledValue = ( sampledValueTemplate: SampledValueTemplate, value: number, context?: MeterValueContext, - phase?: MeterValuePhase, + phase?: MeterValuePhase ): SampledValue => { - const sampledValueContext = context ?? sampledValueTemplate?.context; + const sampledValueContext = context ?? sampledValueTemplate.context const sampledValueLocation = - sampledValueTemplate?.location ?? getMeasurandDefaultLocation(sampledValueTemplate.measurand!); - const sampledValuePhase = phase ?? sampledValueTemplate?.phase; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + sampledValueTemplate.location ?? getMeasurandDefaultLocation(sampledValueTemplate.measurand!) + const sampledValuePhase = phase ?? sampledValueTemplate.phase return { - ...(!isNullOrUndefined(sampledValueTemplate.unit) && { - unit: sampledValueTemplate.unit, + ...(sampledValueTemplate.unit != null && { + unit: sampledValueTemplate.unit }), - ...(!isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }), - ...(!isNullOrUndefined(sampledValueTemplate.measurand) && { - measurand: sampledValueTemplate.measurand, + ...(sampledValueContext != null && { context: sampledValueContext }), + ...(sampledValueTemplate.measurand != null && { + measurand: sampledValueTemplate.measurand }), - ...(!isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }), - ...(!isNullOrUndefined(value) && { value: value.toString() }), - ...(!isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }), - } as SampledValue; -}; + ...(sampledValueLocation != null && { location: sampledValueLocation }), + ...{ value: value.toString() }, + ...(sampledValuePhase != null && { phase: sampledValuePhase }) + } satisfies SampledValue +} const getMeasurandDefaultLocation = ( - measurandType: MeterValueMeasurand, + measurandType: MeterValueMeasurand ): MeterValueLocation | undefined => { switch (measurandType) { case MeterValueMeasurand.STATE_OF_CHARGE: - return MeterValueLocation.EV; + return MeterValueLocation.EV } -}; +} // const getMeasurandDefaultUnit = ( -// measurandType: MeterValueMeasurand, +// measurandType: MeterValueMeasurand // ): MeterValueUnit | undefined => { // switch (measurandType) { // case MeterValueMeasurand.CURRENT_EXPORT: // case MeterValueMeasurand.CURRENT_IMPORT: // case MeterValueMeasurand.CURRENT_OFFERED: -// return MeterValueUnit.AMP; +// return MeterValueUnit.AMP // case MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER: // case MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER: -// return MeterValueUnit.WATT_HOUR; +// return MeterValueUnit.WATT_HOUR // case MeterValueMeasurand.POWER_ACTIVE_EXPORT: // case MeterValueMeasurand.POWER_ACTIVE_IMPORT: // case MeterValueMeasurand.POWER_OFFERED: -// return MeterValueUnit.WATT; +// return MeterValueUnit.WATT // case MeterValueMeasurand.STATE_OF_CHARGE: -// return MeterValueUnit.PERCENT; +// return MeterValueUnit.PERCENT // case MeterValueMeasurand.VOLTAGE: -// return MeterValueUnit.VOLT; +// return MeterValueUnit.VOLT // } -// }; +// } +// eslint-disable-next-line @typescript-eslint/no-extraneous-class export class OCPPServiceUtils { - public static getMessageTypeString = getMessageTypeString; - public static sendAndSetConnectorStatus = sendAndSetConnectorStatus; - public static isIdTagAuthorized = isIdTagAuthorized; - public static buildTransactionEndMeterValue = buildTransactionEndMeterValue; - protected static getSampledValueTemplate = getSampledValueTemplate; - protected static buildSampledValue = buildSampledValue; + public static readonly getMessageTypeString = getMessageTypeString + public static readonly sendAndSetConnectorStatus = sendAndSetConnectorStatus + public static readonly isIdTagAuthorized = isIdTagAuthorized + public static readonly buildTransactionEndMeterValue = buildTransactionEndMeterValue + protected static getSampledValueTemplate = getSampledValueTemplate + protected static buildSampledValue = buildSampledValue - protected constructor() { + protected constructor () { // This is intentional } - public static ajvErrorsToErrorType(errors: ErrorObject[] | null | undefined): ErrorType { - if (isNotEmptyArray(errors) === true) { + public static ajvErrorsToErrorType (errors: ErrorObject[] | undefined | null): ErrorType { + if (isNotEmptyArray(errors)) { for (const error of errors as DefinedError[]) { switch (error.keyword) { case 'type': - return ErrorType.TYPE_CONSTRAINT_VIOLATION; + return ErrorType.TYPE_CONSTRAINT_VIOLATION case 'dependencies': case 'required': - return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION; + return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION case 'pattern': case 'format': - return ErrorType.PROPERTY_CONSTRAINT_VIOLATION; + return ErrorType.PROPERTY_CONSTRAINT_VIOLATION } } } - return ErrorType.FORMAT_VIOLATION; + return ErrorType.FORMAT_VIOLATION } - public static isRequestCommandSupported( + public static isRequestCommandSupported ( chargingStation: ChargingStation, - command: RequestCommand, + command: RequestCommand ): boolean { - const isRequestCommand = Object.values(RequestCommand).includes(command); + const isRequestCommand = Object.values(RequestCommand).includes(command) if ( - isRequestCommand === true && - !chargingStation.stationInfo?.commandsSupport?.outgoingCommands + isRequestCommand && + chargingStation.stationInfo?.commandsSupport?.outgoingCommands == null ) { - return true; + return true } else if ( - isRequestCommand === true && - chargingStation.stationInfo?.commandsSupport?.outgoingCommands?.[command] + isRequestCommand && + chargingStation.stationInfo?.commandsSupport?.outgoingCommands?.[command] != null ) { - return chargingStation.stationInfo?.commandsSupport?.outgoingCommands[command]; + return chargingStation.stationInfo.commandsSupport.outgoingCommands[command] } - logger.error(`${chargingStation.logPrefix()} Unknown outgoing OCPP command '${command}'`); - return false; + logger.error(`${chargingStation.logPrefix()} Unknown outgoing OCPP command '${command}'`) + return false } - public static isIncomingRequestCommandSupported( + public static isIncomingRequestCommandSupported ( chargingStation: ChargingStation, - command: IncomingRequestCommand, + command: IncomingRequestCommand ): boolean { const isIncomingRequestCommand = - Object.values(IncomingRequestCommand).includes(command); + Object.values(IncomingRequestCommand).includes(command) if ( - isIncomingRequestCommand === true && - !chargingStation.stationInfo?.commandsSupport?.incomingCommands + isIncomingRequestCommand && + chargingStation.stationInfo?.commandsSupport?.incomingCommands == null ) { - return true; + return true } else if ( - isIncomingRequestCommand === true && - chargingStation.stationInfo?.commandsSupport?.incomingCommands?.[command] + isIncomingRequestCommand && + chargingStation.stationInfo?.commandsSupport?.incomingCommands[command] != null ) { - return chargingStation.stationInfo?.commandsSupport?.incomingCommands[command]; + return chargingStation.stationInfo.commandsSupport.incomingCommands[command] } - logger.error(`${chargingStation.logPrefix()} Unknown incoming OCPP command '${command}'`); - return false; + logger.error(`${chargingStation.logPrefix()} Unknown incoming OCPP command '${command}'`) + return false } - public static isMessageTriggerSupported( + public static isMessageTriggerSupported ( chargingStation: ChargingStation, - messageTrigger: MessageTrigger, + messageTrigger: MessageTrigger ): boolean { - const isMessageTrigger = Object.values(MessageTrigger).includes(messageTrigger); - if (isMessageTrigger === true && !chargingStation.stationInfo?.messageTriggerSupport) { - return true; + const isMessageTrigger = Object.values(MessageTrigger).includes(messageTrigger) + if (isMessageTrigger && chargingStation.stationInfo?.messageTriggerSupport == null) { + return true } else if ( - isMessageTrigger === true && - chargingStation.stationInfo?.messageTriggerSupport?.[messageTrigger] + isMessageTrigger && + chargingStation.stationInfo?.messageTriggerSupport?.[messageTrigger] != null ) { - return chargingStation.stationInfo?.messageTriggerSupport[messageTrigger]; + return chargingStation.stationInfo.messageTriggerSupport[messageTrigger] } logger.error( - `${chargingStation.logPrefix()} Unknown incoming OCPP message trigger '${messageTrigger}'`, - ); - return false; + `${chargingStation.logPrefix()} Unknown incoming OCPP message trigger '${messageTrigger}'` + ) + return false } - public static isConnectorIdValid( + public static isConnectorIdValid ( chargingStation: ChargingStation, ocppCommand: IncomingRequestCommand, - connectorId: number, + connectorId: number ): boolean { if (connectorId < 0) { logger.error( - `${chargingStation.logPrefix()} ${ocppCommand} incoming request received with invalid connector id ${connectorId}`, - ); - return false; + `${chargingStation.logPrefix()} ${ocppCommand} incoming request received with invalid connector id ${connectorId}` + ) + return false } - return true; + return true } - public static convertDateToISOString(obj: T): void { - for (const key in obj) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - if (isDate(obj![key])) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - (obj![key] as string) = (obj![key] as Date).toISOString(); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - } else if (obj![key] !== null && typeof obj![key] === 'object') { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - OCPPServiceUtils.convertDateToISOString(obj![key] as T); + public static convertDateToISOString(object: T): void { + for (const key in object) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion + if (isDate(object![key])) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion + (object![key] as string) = (object![key] as Date).toISOString() + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-condition + } else if (typeof object![key] === 'object' && object![key] !== null) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion + OCPPServiceUtils.convertDateToISOString(object![key] as T) } } } - public static startHeartbeatInterval(chargingStation: ChargingStation, interval: number): void { - if (chargingStation.heartbeatSetInterval === undefined) { - chargingStation.startHeartbeat(); + public static startHeartbeatInterval (chargingStation: ChargingStation, interval: number): void { + if (chargingStation.heartbeatSetInterval == null) { + chargingStation.startHeartbeat() } else if (chargingStation.getHeartbeatInterval() !== interval) { - chargingStation.restartHeartbeat(); + chargingStation.restartHeartbeat() } } @@ -1337,32 +1355,33 @@ export class OCPPServiceUtils { relativePath: string, ocppVersion: OCPPVersion, moduleName?: string, - methodName?: string, + methodName?: string ): JSONSchemaType { - const filePath = join(dirname(fileURLToPath(import.meta.url)), relativePath); + const filePath = join(dirname(fileURLToPath(import.meta.url)), relativePath) try { - return JSON.parse(readFileSync(filePath, 'utf8')) as JSONSchemaType; + return JSON.parse(readFileSync(filePath, 'utf8')) as JSONSchemaType } catch (error) { handleFileException( filePath, FileType.JsonSchema, error as NodeJS.ErrnoException, OCPPServiceUtils.logPrefix(ocppVersion, moduleName, methodName), - { throwError: false }, - ); - return {} as JSONSchemaType; + { throwError: false } + ) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return {} as JSONSchemaType } } - private static logPrefix = ( + private static readonly logPrefix = ( ocppVersion: OCPPVersion, moduleName?: string, - methodName?: string, + methodName?: string ): string => { const logMsg = isNotEmptyString(moduleName) && isNotEmptyString(methodName) ? ` OCPP ${ocppVersion} | ${moduleName}.${methodName}:` - : ` OCPP ${ocppVersion} |`; - return logPrefix(logMsg); - }; + : ` OCPP ${ocppVersion} |` + return logPrefix(logMsg) + } }