-// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
+// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import { ACElectricUtils, DCElectricUtils } from '../../../utils/ElectricUtils';
-import { CurrentType, Voltage } from '../../../types/ChargingStationTemplate';
-import MeasurandPerPhaseSampledValueTemplates, {
- SampledValueTemplate,
-} from '../../../types/MeasurandPerPhaseSampledValueTemplates';
+import type { JSONSchemaType } from 'ajv';
+
+import { type ChargingStation, ChargingStationUtils } from '../../../charging-station';
+import { OCPPError } from '../../../exception';
import {
+ CurrentType,
+ ErrorType,
+ type JsonType,
+ type MeasurandPerPhaseSampledValueTemplates,
+ type MeasurandValues,
MeterValueContext,
MeterValueLocation,
MeterValueUnit,
- OCPP16MeterValue,
+ OCPP16AuthorizationStatus,
+ type OCPP16AuthorizeRequest,
+ type OCPP16AuthorizeResponse,
+ type OCPP16ChargingProfile,
+ type OCPP16IncomingRequestCommand,
+ type OCPP16MeterValue,
OCPP16MeterValueMeasurand,
OCPP16MeterValuePhase,
- OCPP16SampledValue,
-} from '../../../types/ocpp/1.6/MeterValues';
-import {
- OCPP16IncomingRequestCommand,
OCPP16RequestCommand,
-} from '../../../types/ocpp/1.6/Requests';
-import {
+ type OCPP16SampledValue,
OCPP16StandardParametersKey,
- OCPP16SupportedFeatureProfiles,
-} from '../../../types/ocpp/1.6/Configuration';
-
-import type ChargingStation from '../../ChargingStation';
-import Constants from '../../../utils/Constants';
-import { ErrorType } from '../../../types/ocpp/ErrorType';
-import MeasurandValues from '../../../types/MeasurandValues';
-import OCPPError from '../../../exception/OCPPError';
+ type OCPP16SupportedFeatureProfiles,
+ OCPPVersion,
+ type SampledValueTemplate,
+ Voltage,
+} from '../../../types';
+import { ACElectricUtils, Constants, DCElectricUtils, Utils, logger } from '../../../utils';
import { OCPPServiceUtils } from '../OCPPServiceUtils';
-import Utils from '../../../utils/Utils';
-import logger from '../../../utils/Logger';
export class OCPP16ServiceUtils extends OCPPServiceUtils {
public static checkFeatureProfile(
debug = false
): OCPP16MeterValue {
const meterValue: OCPP16MeterValue = {
- timestamp: new Date().toISOString(),
+ timestamp: new Date(),
sampledValue: [],
};
const connector = chargingStation.getConnectorStatus(connectorId);
// SoC measurand
- const socSampledValueTemplate = chargingStation.getSampledValueTemplate(
+ const socSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.STATE_OF_CHARGE
);
if (socSampledValueTemplate) {
+ const socMaximumValue = 100;
+ const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0;
const socSampledValueTemplateValue = socSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
parseInt(socSampledValueTemplate.value),
socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomInteger(100);
+ : Utils.getRandomInteger(socMaximumValue, socMinimumValue);
meterValue.sampledValue.push(
OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue)
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
- if (Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > 100 || debug) {
+ if (
+ Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > socMaximumValue ||
+ Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) < socMinimumValue ||
+ debug
+ ) {
logger.error(
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+ }: connector id ${connectorId}, transaction id ${
+ connector?.transactionId
+ }, value: ${socMinimumValue}/${
meterValue.sampledValue[sampledValuesIndex].value
- }/100`
+ }/${socMaximumValue}}`
);
}
}
// Voltage measurand
- const voltageSampledValueTemplate = chargingStation.getSampledValueTemplate(
+ const voltageSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.VOLTAGE
);
) {
const phaseLineToNeutralValue = `L${phase}-N`;
const voltagePhaseLineToNeutralSampledValueTemplate =
- chargingStation.getSampledValueTemplate(
+ OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.VOLTAGE,
phaseLineToNeutralValue as OCPP16MeterValuePhase
OCPP16ServiceUtils.buildSampledValue(
voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue,
- null,
+ undefined,
phaseLineToNeutralValue as OCPP16MeterValuePhase
)
);
: chargingStation.getNumberOfPhases()
}`;
const voltagePhaseLineToLineSampledValueTemplate =
- chargingStation.getSampledValueTemplate(
+ OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.VOLTAGE,
phaseLineToLineValue as OCPP16MeterValuePhase
OCPP16ServiceUtils.buildSampledValue(
voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue,
- null,
+ undefined,
phaseLineToLineValue as OCPP16MeterValuePhase
)
);
}
}
// Power.Active.Import measurand
- const powerSampledValueTemplate = chargingStation.getSampledValueTemplate(
+ const powerSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT
);
let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
if (chargingStation.getNumberOfPhases() === 3) {
powerPerPhaseSampledValueTemplates = {
- L1: chargingStation.getSampledValueTemplate(
+ L1: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
OCPP16MeterValuePhase.L1_N
),
- L2: chargingStation.getSampledValueTemplate(
+ L2: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
OCPP16MeterValuePhase.L2_N
),
- L3: chargingStation.getSampledValueTemplate(
+ L3: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
OCPP16MeterValuePhase.L3_N
chargingStation,
powerSampledValueTemplate.measurand
);
- const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+ const errMsg = `MeterValues measurand ${
powerSampledValueTemplate.measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
const connectorMaximumPowerPerPhase = Math.round(
connectorMaximumAvailablePower / chargingStation.getNumberOfPhases()
);
+ const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue) ?? 0;
+ const connectorMinimumPowerPerPhase = Math.round(
+ connectorMinimumPower / chargingStation.getNumberOfPhases()
+ );
switch (chargingStation.getCurrentOutType()) {
case CurrentType.AC:
if (chargingStation.getNumberOfPhases() === 3) {
powerMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(
+ connectorMaximumPowerPerPhase / unitDivider,
+ connectorMinimumPowerPerPhase / unitDivider
+ );
powerMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(
+ connectorMaximumPowerPerPhase / unitDivider,
+ connectorMinimumPowerPerPhase / unitDivider
+ );
powerMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(
+ connectorMaximumPowerPerPhase / unitDivider,
+ connectorMinimumPowerPerPhase / unitDivider
+ );
} else {
powerMeasurandValues.L1 = powerSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
+ : Utils.getRandomFloatRounded(
+ connectorMaximumPower / unitDivider,
+ connectorMinimumPower / unitDivider
+ );
powerMeasurandValues.L2 = 0;
powerMeasurandValues.L3 = 0;
}
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
+ : Utils.getRandomFloatRounded(
+ connectorMaximumPower / unitDivider,
+ connectorMinimumPower / unitDivider
+ );
break;
default:
- logger.error(errMsg);
+ logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
}
meterValue.sampledValue.push(
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
const connectorMaximumPowerRounded = Utils.roundTo(connectorMaximumPower / unitDivider, 2);
+ const connectorMinimumPowerRounded = Utils.roundTo(connectorMinimumPower / unitDivider, 2);
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
connectorMaximumPowerRounded ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
+ connectorMinimumPowerRounded ||
debug
) {
logger.error(
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+ }: connector id ${connectorId}, transaction id ${
+ connector?.transactionId
+ }, value: ${connectorMinimumPowerRounded}/${
meterValue.sampledValue[sampledValuesIndex].value
}/${connectorMaximumPowerRounded}`
);
(powerPerPhaseSampledValueTemplates[`L${phase}`] as SampledValueTemplate) ??
powerSampledValueTemplate,
powerMeasurandValues[`L${phase}`] as number,
- null,
+ undefined,
phaseValue as OCPP16MeterValuePhase
)
);
connectorMaximumPowerPerPhase / unitDivider,
2
);
+ const connectorMinimumPowerPerPhaseRounded = Utils.roundTo(
+ connectorMinimumPowerPerPhase / unitDivider,
+ 2
+ );
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
connectorMaximumPowerPerPhaseRounded ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
+ connectorMinimumPowerPerPhaseRounded ||
debug
) {
logger.error(
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: phase ${
meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
- }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+ }, connector id ${connectorId}, transaction id ${
+ connector?.transactionId
+ }, value: ${connectorMinimumPowerPerPhaseRounded}/${
meterValue.sampledValue[sampledValuesPerPhaseIndex].value
}/${connectorMaximumPowerPerPhaseRounded}`
);
}
}
// Current.Import measurand
- const currentSampledValueTemplate = chargingStation.getSampledValueTemplate(
+ const currentSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.CURRENT_IMPORT
);
let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
if (chargingStation.getNumberOfPhases() === 3) {
currentPerPhaseSampledValueTemplates = {
- L1: chargingStation.getSampledValueTemplate(
+ L1: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.CURRENT_IMPORT,
OCPP16MeterValuePhase.L1
),
- L2: chargingStation.getSampledValueTemplate(
+ L2: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.CURRENT_IMPORT,
OCPP16MeterValuePhase.L2
),
- L3: chargingStation.getSampledValueTemplate(
+ L3: OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
connectorId,
OCPP16MeterValueMeasurand.CURRENT_IMPORT,
OCPP16MeterValuePhase.L3
chargingStation,
currentSampledValueTemplate.measurand
);
- const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+ const errMsg = `MeterValues measurand ${
currentSampledValueTemplate.measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
const connectorMaximumAvailablePower =
chargingStation.getConnectorMaximumAvailablePower(connectorId);
+ const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0;
let connectorMaximumAmperage: number;
switch (chargingStation.getCurrentOutType()) {
case CurrentType.AC:
currentMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
currentMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
currentMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(connectorMaximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
} else {
currentMeasurandValues.L1 = currentSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(connectorMaximumAmperage);
+ : Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
currentMeasurandValues.L2 = 0;
currentMeasurandValues.L3 = 0;
}
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(connectorMaximumAmperage);
+ : Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
break;
default:
- logger.error(errMsg);
+ logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
}
meterValue.sampledValue.push(
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
connectorMaximumAmperage ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
+ connectorMinimumAmperage ||
debug
) {
logger.error(
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+ }: connector id ${connectorId}, transaction id ${
+ connector?.transactionId
+ }, value: ${connectorMinimumAmperage}/${
meterValue.sampledValue[sampledValuesIndex].value
}/${connectorMaximumAmperage}`
);
(currentPerPhaseSampledValueTemplates[phaseValue] as SampledValueTemplate) ??
currentSampledValueTemplate,
currentMeasurandValues[phaseValue] as number,
- null,
+ undefined,
phaseValue as OCPP16MeterValuePhase
)
);
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
connectorMaximumAmperage ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
+ connectorMinimumAmperage ||
debug
) {
logger.error(
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: phase ${
meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
- }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+ }, connector id ${connectorId}, transaction id ${
+ connector?.transactionId
+ }, value: ${connectorMinimumAmperage}/${
meterValue.sampledValue[sampledValuesPerPhaseIndex].value
}/${connectorMaximumAmperage}`
);
}
}
// Energy.Active.Import.Register measurand (default)
- const energySampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
+ const energySampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
+ connectorId
+ );
if (energySampledValueTemplate) {
OCPP16ServiceUtils.checkMeasurandPowerDivider(
chargingStation,
// 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;
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connectorId ${connectorId}, transaction ${
- connector.transactionId
+ }: connector id ${connectorId}, transaction id ${
+ connector?.transactionId
}, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${Utils.roundTo(
interval / (3600 * 1000),
4
meterStart: number
): OCPP16MeterValue {
const meterValue: OCPP16MeterValue = {
- timestamp: new Date().toISOString(),
+ timestamp: new Date(),
sampledValue: [],
};
// Energy.Active.Import.Register measurand (default)
- const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
+ const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
+ connectorId
+ );
const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
meterValue.sampledValue.push(
OCPP16ServiceUtils.buildSampledValue(
sampledValueTemplate,
- Utils.roundTo(meterStart / unitDivider, 4),
+ Utils.roundTo((meterStart ?? 0) / unitDivider, 4),
MeterValueContext.TRANSACTION_BEGIN
)
);
meterStop: number
): OCPP16MeterValue {
const meterValue: OCPP16MeterValue = {
- timestamp: new Date().toISOString(),
+ timestamp: new Date(),
sampledValue: [],
};
// Energy.Active.Import.Register measurand (default)
- const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
+ const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
+ chargingStation,
+ connectorId
+ );
const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
meterValue.sampledValue.push(
OCPP16ServiceUtils.buildSampledValue(
sampledValueTemplate,
- Utils.roundTo(meterStop / unitDivider, 4),
+ Utils.roundTo((meterStop ?? 0) / unitDivider, 4),
MeterValueContext.TRANSACTION_END
)
);
return meterValues;
}
+ public static setChargingProfile(
+ chargingStation: ChargingStation,
+ connectorId: number,
+ cp: OCPP16ChargingProfile
+ ): void {
+ if (
+ Utils.isNullOrUndefined(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)
+ ) {
+ logger.error(
+ `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId} with an uninitialized charging profiles array attribute, applying deferred initialization`
+ );
+ chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
+ }
+ if (
+ Array.isArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles) === false
+ ) {
+ logger.error(
+ `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId} with an improper attribute type for the charging profiles array, applying proper type initialization`
+ );
+ chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
+ }
+ let cpReplaced = false;
+ if (Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) {
+ chargingStation
+ .getConnectorStatus(connectorId)
+ ?.chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
+ if (
+ chargingProfile.chargingProfileId === cp.chargingProfileId ||
+ (chargingProfile.stackLevel === cp.stackLevel &&
+ chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)
+ ) {
+ chargingStation.getConnectorStatus(connectorId).chargingProfiles[index] = cp;
+ cpReplaced = true;
+ }
+ });
+ }
+ !cpReplaced && chargingStation.getConnectorStatus(connectorId)?.chargingProfiles?.push(cp);
+ }
+
+ public static parseJsonSchemaFile<T extends JsonType>(
+ relativePath: string,
+ moduleName?: string,
+ methodName?: string
+ ): JSONSchemaType<T> {
+ return super.parseJsonSchemaFile<T>(
+ relativePath,
+ OCPPVersion.VERSION_16,
+ moduleName,
+ methodName
+ );
+ }
+
+ public static async isIdTagAuthorized(
+ chargingStation: ChargingStation,
+ connectorId: number,
+ idTag: string,
+ parentIdTag?: string
+ ): Promise<boolean> {
+ let authorized = false;
+ const connectorStatus = chargingStation.getConnectorStatus(connectorId);
+ if (OCPP16ServiceUtils.isIdTagLocalAuthorized(chargingStation, idTag)) {
+ connectorStatus.localAuthorizeIdTag = idTag;
+ connectorStatus.idTagLocalAuthorized = true;
+ authorized = true;
+ } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
+ connectorStatus.authorizeIdTag = idTag;
+ authorized = await OCPP16ServiceUtils.isIdTagRemoteAuthorized(chargingStation, idTag);
+ } else {
+ logger.warn(
+ `${chargingStation.logPrefix()} The charging station configuration expects authorize at
+ remote start transaction but local authorization or authorize isn't enabled`
+ );
+ }
+ return authorized;
+ }
+
private static buildSampledValue(
sampledValueTemplate: SampledValueTemplate,
value: number,
chargingStation: ChargingStation,
measurandType: OCPP16MeterValueMeasurand
): void {
- if (Utils.isUndefined(chargingStation.stationInfo.powerDivider)) {
- const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+ if (Utils.isUndefined(chargingStation.powerDivider)) {
+ const errMsg = `MeterValues measurand ${
measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: powerDivider is undefined`;
- logger.error(errMsg);
+ logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
- } else if (chargingStation.stationInfo?.powerDivider <= 0) {
- const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+ } else if (chargingStation?.powerDivider <= 0) {
+ const errMsg = `MeterValues measurand ${
measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
- logger.error(errMsg);
+ }: powerDivider have zero or below value ${chargingStation.powerDivider}`;
+ logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
}
}
return MeterValueUnit.VOLT;
}
}
+
+ private static isIdTagLocalAuthorized(chargingStation: ChargingStation, idTag: string): boolean {
+ return (
+ chargingStation.getLocalAuthListEnabled() === true &&
+ chargingStation.hasIdTags() === true &&
+ Utils.isNotEmptyString(
+ chargingStation.idTagsCache
+ .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo))
+ ?.find((tag) => tag === idTag)
+ )
+ );
+ }
+
+ private static async isIdTagRemoteAuthorized(
+ chargingStation: ChargingStation,
+ idTag: string
+ ): Promise<boolean> {
+ const authorizeResponse: OCPP16AuthorizeResponse =
+ await chargingStation.ocppRequestService.requestHandler<
+ OCPP16AuthorizeRequest,
+ OCPP16AuthorizeResponse
+ >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
+ idTag: idTag,
+ });
+ return authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED;
+ }
}