X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCPP16ServiceUtils.ts;h=eceb21488f6e4e320a19d9d1df52bd6c43b98c31;hb=53ac516c575adaacd199a68d39b5ace22876ee83;hp=2dc498e82a28a5071a8cc0ce48449ce7509afefa;hpb=ed3d28080b6597ba2f728d625e34ce05aea49d06;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts index 2dc498e8..eceb2148 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts @@ -1,13 +1,19 @@ -// Partial Copyright Jerome Benoit. 2021. All Rights Reserved. +// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved. + +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import type { JSONSchemaType } from 'ajv'; -import BaseError from '../../../exception/BaseError'; import OCPPError from '../../../exception/OCPPError'; import { CurrentType, Voltage } from '../../../types/ChargingStationTemplate'; +import type { JsonType } from '../../../types/JsonType'; import type { MeasurandPerPhaseSampledValueTemplates, SampledValueTemplate, } from '../../../types/MeasurandPerPhaseSampledValueTemplates'; import type { MeasurandValues } from '../../../types/MeasurandValues'; +import type { OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile'; import { OCPP16StandardParametersKey, OCPP16SupportedFeatureProfiles, @@ -16,25 +22,22 @@ import { MeterValueContext, MeterValueLocation, MeterValueUnit, - OCPP16MeterValue, + type OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase, - OCPP16SampledValue, + type OCPP16SampledValue, } from '../../../types/ocpp/1.6/MeterValues'; import { - OCPP16IncomingRequestCommand, + type OCPP16IncomingRequestCommand, OCPP16RequestCommand, } from '../../../types/ocpp/1.6/Requests'; -import type { ChargingProfile } from '../../../types/ocpp/ChargingProfile'; -import { StandardParametersKey } from '../../../types/ocpp/Configuration'; import { ErrorType } from '../../../types/ocpp/ErrorType'; -import { MeterValueMeasurand, type MeterValuePhase } from '../../../types/ocpp/MeterValues'; +import { OCPPVersion } from '../../../types/ocpp/OCPPVersion'; import Constants from '../../../utils/Constants'; import { ACElectricUtils, DCElectricUtils } from '../../../utils/ElectricUtils'; import logger from '../../../utils/Logger'; import Utils from '../../../utils/Utils'; import type ChargingStation from '../../ChargingStation'; -import { ChargingStationConfigurationUtils } from '../../ChargingStationConfigurationUtils'; import { OCPPServiceUtils } from '../OCPPServiceUtils'; export class OCPP16ServiceUtils extends OCPPServiceUtils { @@ -62,7 +65,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { debug = false ): OCPP16MeterValue { const meterValue: OCPP16MeterValue = { - timestamp: new Date().toISOString(), + timestamp: new Date(), sampledValue: [], }; const connector = chargingStation.getConnectorStatus(connectorId); @@ -88,7 +91,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { `${chargingStation.logPrefix()} MeterValues measurand ${ meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${ + }: connectorId ${connectorId}, transaction ${connector?.transactionId}, value: ${ meterValue.sampledValue[sampledValuesIndex].value }/100` ); @@ -149,7 +152,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { OCPP16ServiceUtils.buildSampledValue( voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate, voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue, - null, + undefined, phaseLineToNeutralValue as OCPP16MeterValuePhase ) ); @@ -188,7 +191,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { OCPP16ServiceUtils.buildSampledValue( voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate, voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue, - null, + undefined, phaseLineToLineValue as OCPP16MeterValuePhase ) ); @@ -359,7 +362,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { `${chargingStation.logPrefix()} MeterValues measurand ${ meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${ + }: connectorId ${connectorId}, transaction ${connector?.transactionId}, value: ${ meterValue.sampledValue[sampledValuesIndex].value }/${connectorMaximumPowerRounded}` ); @@ -375,7 +378,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { (powerPerPhaseSampledValueTemplates[`L${phase}`] as SampledValueTemplate) ?? powerSampledValueTemplate, powerMeasurandValues[`L${phase}`] as number, - null, + undefined, phaseValue as OCPP16MeterValuePhase ) ); @@ -395,7 +398,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: phase ${ meterValue.sampledValue[sampledValuesPerPhaseIndex].phase - }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${ + }, connectorId ${connectorId}, transaction ${connector?.transactionId}, value: ${ meterValue.sampledValue[sampledValuesPerPhaseIndex].value }/${connectorMaximumPowerPerPhaseRounded}` ); @@ -571,7 +574,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { `${chargingStation.logPrefix()} MeterValues measurand ${ meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${ + }: connectorId ${connectorId}, transaction ${connector?.transactionId}, value: ${ meterValue.sampledValue[sampledValuesIndex].value }/${connectorMaximumAmperage}` ); @@ -587,7 +590,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { (currentPerPhaseSampledValueTemplates[phaseValue] as SampledValueTemplate) ?? currentSampledValueTemplate, currentMeasurandValues[phaseValue] as number, - null, + undefined, phaseValue as OCPP16MeterValuePhase ) ); @@ -603,7 +606,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: phase ${ meterValue.sampledValue[sampledValuesPerPhaseIndex].phase - }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${ + }, connectorId ${connectorId}, transaction ${connector?.transactionId}, value: ${ meterValue.sampledValue[sampledValuesPerPhaseIndex].value }/${connectorMaximumAmperage}` ); @@ -645,9 +648,9 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { // Persist previous value on connector if ( connector && - !Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) && + Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) === false && connector.energyActiveImportRegisterValue >= 0 && - !Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) && + Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false && connector.transactionEnergyActiveImportRegisterValue >= 0 ) { connector.energyActiveImportRegisterValue += energyValueRounded; @@ -673,7 +676,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER }: connectorId ${connectorId}, transaction ${ - connector.transactionId + connector?.transactionId }, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${Utils.roundTo( interval / (3600 * 1000), 4 @@ -690,7 +693,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { meterStart: number ): OCPP16MeterValue { const meterValue: OCPP16MeterValue = { - timestamp: new Date().toISOString(), + timestamp: new Date(), sampledValue: [], }; // Energy.Active.Import.Register measurand (default) @@ -702,7 +705,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { meterValue.sampledValue.push( OCPP16ServiceUtils.buildSampledValue( sampledValueTemplate, - Utils.roundTo(meterStart / unitDivider, 4), + Utils.roundTo((meterStart ?? 0) / unitDivider, 4), MeterValueContext.TRANSACTION_BEGIN ) ); @@ -715,7 +718,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { meterStop: number ): OCPP16MeterValue { const meterValue: OCPP16MeterValue = { - timestamp: new Date().toISOString(), + timestamp: new Date(), sampledValue: [], }; // Energy.Active.Import.Register measurand (default) @@ -727,7 +730,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { meterValue.sampledValue.push( OCPP16ServiceUtils.buildSampledValue( sampledValueTemplate, - Utils.roundTo(meterStop / unitDivider, 4), + Utils.roundTo((meterStop ?? 0) / unitDivider, 4), MeterValueContext.TRANSACTION_END ) ); @@ -747,25 +750,29 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { public static setChargingProfile( chargingStation: ChargingStation, connectorId: number, - cp: ChargingProfile + cp: OCPP16ChargingProfile ): void { - if (Utils.isNullOrUndefined(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) { + if ( + Utils.isNullOrUndefined(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles) + ) { logger.error( `${chargingStation.logPrefix()} Trying to set a charging profile on connectorId ${connectorId} with an uninitialized charging profiles array attribute, applying deferred initialization` ); chargingStation.getConnectorStatus(connectorId).chargingProfiles = []; } - if (Array.isArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles) === false) { + if ( + Array.isArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles) === false + ) { logger.error( `${chargingStation.logPrefix()} Trying to set a charging profile on connectorId ${connectorId} with an improper attribute type for the charging profiles array, applying proper type initialization` ); chargingStation.getConnectorStatus(connectorId).chargingProfiles = []; } let cpReplaced = false; - if (!Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) { + if (Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) { chargingStation .getConnectorStatus(connectorId) - .chargingProfiles?.forEach((chargingProfile: ChargingProfile, index: number) => { + ?.chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => { if ( chargingProfile.chargingProfileId === cp.chargingProfileId || (chargingProfile.stackLevel === cp.stackLevel && @@ -776,87 +783,19 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils { } }); } - !cpReplaced && chargingStation.getConnectorStatus(connectorId).chargingProfiles?.push(cp); + !cpReplaced && chargingStation.getConnectorStatus(connectorId)?.chargingProfiles?.push(cp); } - private static getSampledValueTemplate( - chargingStation: ChargingStation, - connectorId: number, - measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER, - phase?: MeterValuePhase - ): SampledValueTemplate | undefined { - const onPhaseStr = phase ? `on phase ${phase} ` : ''; - if (Constants.SUPPORTED_MEASURANDS.includes(measurand) === false) { - logger.warn( - `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` - ); - return; - } - if ( - measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - !ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) - ) { - logger.debug( - `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId} not found in '${ - StandardParametersKey.MeterValuesSampledData - }' OCPP parameter` - ); - return; - } - const sampledValueTemplates: SampledValueTemplate[] = - chargingStation.getConnectorStatus(connectorId).MeterValues; - for ( - let index = 0; - !Utils.isEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length; - index++ - ) { - if ( - Constants.SUPPORTED_MEASURANDS.includes( - sampledValueTemplates[index]?.measurand ?? - MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER - ) === false - ) { - logger.warn( - `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` - ); - } else if ( - phase && - sampledValueTemplates[index]?.phase === phase && - sampledValueTemplates[index]?.measurand === measurand && - ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) === true - ) { - return sampledValueTemplates[index]; - } else if ( - !phase && - !sampledValueTemplates[index].phase && - sampledValueTemplates[index]?.measurand === measurand && - ChargingStationConfigurationUtils.getConfigurationKey( - chargingStation, - StandardParametersKey.MeterValuesSampledData - )?.value.includes(measurand) === true - ) { - return sampledValueTemplates[index]; - } else if ( - measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - (!sampledValueTemplates[index].measurand || - sampledValueTemplates[index].measurand === measurand) - ) { - return sampledValueTemplates[index]; - } - } - if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connectorId ${connectorId}`; - logger.error(`${chargingStation.logPrefix()} ${errorMsg}`); - throw new BaseError(errorMsg); - } - logger.debug( - `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` + public static parseJsonSchemaFile( + relativePath: string, + moduleName?: string, + methodName?: string + ): JSONSchemaType { + return super.parseJsonSchemaFile( + path.resolve(path.dirname(fileURLToPath(import.meta.url)), relativePath), + OCPPVersion.VERSION_16, + moduleName, + methodName ); }