import chalk from 'chalk';
import moment from 'moment';
-import type { ChargingStation } from './internal';
+import type { ChargingStation } from './ChargingStation';
import { BaseError } from '../exception';
import {
AmpereUnits,
type ChargingSchedulePeriod,
type ChargingStationInfo,
type ChargingStationTemplate,
+ ConnectorPhaseRotation,
type ConnectorStatus,
+ ConnectorStatusEnum,
CurrentType,
type EvseTemplate,
type OCPP16BootNotificationRequest,
RecurrencyKindType,
Voltage,
} from '../types';
-import {
- ACElectricUtils,
- Configuration,
- Constants,
- DCElectricUtils,
- Utils,
- logger,
-} from '../utils';
-import { WorkerProcessType } from '../worker';
+import { ACElectricUtils, Constants, DCElectricUtils, Utils, logger } from '../utils';
const moduleName = 'ChargingStationUtils';
return true;
}
+ public static getPhaseRotationValue(
+ connectorId: number,
+ numberOfPhases: number
+ ): string | undefined {
+ // AC/DC
+ if (connectorId === 0 && numberOfPhases === 0) {
+ return `${connectorId}.${ConnectorPhaseRotation.RST}`;
+ } else if (connectorId > 0 && numberOfPhases === 0) {
+ return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
+ // AC
+ } else if (connectorId > 0 && numberOfPhases === 1) {
+ return `${connectorId}.${ConnectorPhaseRotation.NotApplicable}`;
+ } else if (connectorId > 0 && numberOfPhases === 3) {
+ return `${connectorId}.${ConnectorPhaseRotation.RST}`;
+ }
+ }
+
public static getMaxNumberOfEvses(evses: Record<string, EvseTemplate>): number {
if (!evses) {
return -1;
return Object.keys(connectors).length;
}
- public static checkTemplateMaxConnectors(
- templateMaxConnectors: number,
- templateFile: string,
- logPrefix: string
- ): void {
- if (templateMaxConnectors === 0) {
- logger.warn(
- `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration`
- );
- } else if (templateMaxConnectors < 0) {
- logger.error(
- `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined`
- );
+ public static getBootConnectorStatus(
+ chargingStation: ChargingStation,
+ connectorId: number,
+ connectorStatus: ConnectorStatus
+ ): ConnectorStatusEnum {
+ let connectorBootStatus: ConnectorStatusEnum;
+ if (
+ !connectorStatus?.status &&
+ (chargingStation.isChargingStationAvailable() === false ||
+ chargingStation.isConnectorAvailable(connectorId) === false)
+ ) {
+ connectorBootStatus = ConnectorStatusEnum.Unavailable;
+ } else if (!connectorStatus?.status && connectorStatus?.bootStatus) {
+ // Set boot status in template at startup
+ connectorBootStatus = connectorStatus?.bootStatus;
+ } else if (connectorStatus?.status) {
+ // Set previous status at startup
+ connectorBootStatus = connectorStatus?.status;
+ } else {
+ // Set default status
+ connectorBootStatus = ConnectorStatusEnum.Available;
}
+ return connectorBootStatus;
}
- public static getConfiguredNumberOfConnectors(stationInfo: ChargingStationInfo): number {
- let configuredMaxConnectors: number;
- if (Utils.isNotEmptyArray(stationInfo.numberOfConnectors) === true) {
- const numberOfConnectors = stationInfo.numberOfConnectors as number[];
- configuredMaxConnectors =
- numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
- } else if (Utils.isUndefined(stationInfo.numberOfConnectors) === false) {
- configuredMaxConnectors = stationInfo.numberOfConnectors as number;
- } else if (stationInfo.Connectors && !stationInfo.Evses) {
- configuredMaxConnectors = stationInfo?.Connectors[0]
- ? ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors) - 1
- : ChargingStationUtils.getMaxNumberOfConnectors(stationInfo.Connectors);
- } else if (stationInfo.Evses && !stationInfo.Connectors) {
- configuredMaxConnectors = 0;
- for (const evse in stationInfo.Evses) {
- if (evse === '0') {
- continue;
- }
- configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
- stationInfo.Evses[evse].Connectors
- );
- }
+ public static checkTemplate(
+ stationTemplate: ChargingStationTemplate,
+ logPrefix: string,
+ templateFile: string
+ ) {
+ if (Utils.isNullOrUndefined(stationTemplate)) {
+ const errorMsg = `Failed to read charging station template file ${templateFile}`;
+ logger.error(`${logPrefix} ${errorMsg}`);
+ throw new BaseError(errorMsg);
+ }
+ if (Utils.isEmptyObject(stationTemplate)) {
+ const errorMsg = `Empty charging station information from template file ${templateFile}`;
+ logger.error(`${logPrefix} ${errorMsg}`);
+ throw new BaseError(errorMsg);
+ }
+ if (Utils.isEmptyObject(stationTemplate.AutomaticTransactionGenerator)) {
+ stationTemplate.AutomaticTransactionGenerator = Constants.DEFAULT_ATG_CONFIGURATION;
+ logger.warn(
+ `${logPrefix} Empty automatic transaction generator configuration from template file ${templateFile}, set to default: %j`,
+ Constants.DEFAULT_ATG_CONFIGURATION
+ );
+ }
+ if (
+ Utils.isNullOrUndefined(stationTemplate.idTagsFile) ||
+ Utils.isEmptyString(stationTemplate.idTagsFile)
+ ) {
+ logger.warn(
+ `${logPrefix} Missing id tags file in template file ${templateFile}. That can lead to issues with the Automatic Transaction Generator`
+ );
}
- return configuredMaxConnectors;
}
- public static checkConfiguredMaxConnectors(
- configuredMaxConnectors: number,
- templateFile: string,
- logPrefix: string
- ): void {
- if (configuredMaxConnectors <= 0) {
+ public static checkConnectorsConfiguration(
+ stationTemplate: ChargingStationTemplate,
+ logPrefix: string,
+ templateFile: string
+ ): {
+ configuredMaxConnectors: number;
+ templateMaxConnectors: number;
+ templateMaxAvailableConnectors: number;
+ } {
+ const configuredMaxConnectors =
+ ChargingStationUtils.getConfiguredNumberOfConnectors(stationTemplate);
+ ChargingStationUtils.checkConfiguredMaxConnectors(
+ configuredMaxConnectors,
+ logPrefix,
+ templateFile
+ );
+ const templateMaxConnectors = ChargingStationUtils.getMaxNumberOfConnectors(
+ stationTemplate.Connectors
+ );
+ ChargingStationUtils.checkTemplateMaxConnectors(templateMaxConnectors, logPrefix, templateFile);
+ const templateMaxAvailableConnectors = stationTemplate?.Connectors[0]
+ ? templateMaxConnectors - 1
+ : templateMaxConnectors;
+ if (
+ configuredMaxConnectors > templateMaxAvailableConnectors &&
+ !stationTemplate?.randomConnectors
+ ) {
logger.warn(
- `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+ `${logPrefix} Number of connectors exceeds the number of connector configurations in template ${templateFile}, forcing random connector configurations affectation`
);
+ stationTemplate.randomConnectors = true;
}
+ return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors };
}
public static checkStationInfoConnectorStatus(
}
}
- public static workerPoolInUse(): boolean {
- return [WorkerProcessType.dynamicPool, WorkerProcessType.staticPool].includes(
- Configuration.getWorker().processType
- );
- }
-
- public static workerDynamicPoolInUse(): boolean {
- return Configuration.getWorker().processType === WorkerProcessType.dynamicPool;
- }
-
public static warnTemplateKeysDeprecation(
- templateFile: string,
stationTemplate: ChargingStationTemplate,
- logPrefix: string
+ logPrefix: string,
+ templateFile: string
) {
const templateKeys: { key: string; deprecatedKey: string }[] = [
{ key: 'supervisionUrls', deprecatedKey: 'supervisionUrl' },
ChargingStationUtils.warnDeprecatedTemplateKey(
stationTemplate,
templateKey.deprecatedKey,
- templateFile,
logPrefix,
+ templateFile,
`Use '${templateKey.key}' instead`
);
ChargingStationUtils.convertDeprecatedTemplateKey(
public static stationTemplateToStationInfo(
stationTemplate: ChargingStationTemplate
): ChargingStationInfo {
- stationTemplate = Utils.cloneObject(stationTemplate);
+ stationTemplate = Utils.cloneObject<ChargingStationTemplate>(stationTemplate);
delete stationTemplate.power;
delete stationTemplate.powerUnit;
+ delete stationTemplate?.Connectors;
+ delete stationTemplate?.Evses;
delete stationTemplate.Configuration;
delete stationTemplate.AutomaticTransactionGenerator;
delete stationTemplate.chargeBoxSerialNumberPrefix;
return stationTemplate as unknown as ChargingStationInfo;
}
- public static createStationInfoHash(stationInfo: ChargingStationInfo): void {
- delete stationInfo.infoHash;
- stationInfo.infoHash = crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
- .update(JSON.stringify(stationInfo))
- .digest('hex');
- }
-
public static createSerialNumber(
stationTemplate: ChargingStationTemplate,
stationInfo: ChargingStationInfo,
randomSerialNumber: true,
}
): void {
- params = params ?? {};
- params.randomSerialNumberUpperCase = params?.randomSerialNumberUpperCase ?? true;
- params.randomSerialNumber = params?.randomSerialNumber ?? true;
+ params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params };
const serialNumberSuffix = params?.randomSerialNumber
? ChargingStationUtils.getRandomSerialNumberSuffix({
upperCase: params.randomSerialNumberUpperCase,
})
: '';
- stationInfo.chargePointSerialNumber = Utils.isNotEmptyString(
- stationTemplate?.chargePointSerialNumberPrefix
- )
- ? `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`
- : undefined;
- stationInfo.chargeBoxSerialNumber = Utils.isNotEmptyString(
- stationTemplate?.chargeBoxSerialNumberPrefix
- )
- ? `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`
- : undefined;
- stationInfo.meterSerialNumber = Utils.isNotEmptyString(stationTemplate?.meterSerialNumberPrefix)
- ? `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`
- : undefined;
+ Utils.isNotEmptyString(stationTemplate?.chargePointSerialNumberPrefix) &&
+ (stationInfo.chargePointSerialNumber = `${stationTemplate.chargePointSerialNumberPrefix}${serialNumberSuffix}`);
+ Utils.isNotEmptyString(stationTemplate?.chargeBoxSerialNumberPrefix) &&
+ (stationInfo.chargeBoxSerialNumber = `${stationTemplate.chargeBoxSerialNumberPrefix}${serialNumberSuffix}`);
+ Utils.isNotEmptyString(stationTemplate?.meterSerialNumberPrefix) &&
+ (stationInfo.meterSerialNumber = `${stationTemplate.meterSerialNumberPrefix}${serialNumberSuffix}`);
}
public static propagateSerialNumber(
let limit: number, matchingChargingProfile: ChargingProfile;
// Get charging profiles for connector and sort by stack level
const chargingProfiles =
- Utils.cloneObject(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)?.sort(
- (a, b) => b.stackLevel - a.stackLevel
- ) ?? [];
+ Utils.cloneObject<ChargingProfile[]>(
+ chargingStation.getConnectorStatus(connectorId)?.chargingProfiles
+ )?.sort((a, b) => b.stackLevel - a.stackLevel) ?? [];
// Get profiles on connector 0
if (chargingStation.getConnectorStatus(0)?.chargingProfiles) {
chargingProfiles.push(
- ...Utils.cloneObject(chargingStation.getConnectorStatus(0).chargingProfiles).sort(
- (a, b) => b.stackLevel - a.stackLevel
- )
+ ...Utils.cloneObject<ChargingProfile[]>(
+ chargingStation.getConnectorStatus(0).chargingProfiles
+ ).sort((a, b) => b.stackLevel - a.stackLevel)
);
}
if (Utils.isNotEmptyArray(chargingProfiles)) {
public static getDefaultVoltageOut(
currentType: CurrentType,
- templateFile: string,
- logPrefix: string
+ logPrefix: string,
+ templateFile: string
): Voltage {
- const errMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
+ const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
let defaultVoltageOut: number;
switch (currentType) {
case CurrentType.AC:
defaultVoltageOut = Voltage.VOLTAGE_400;
break;
default:
- logger.error(`${logPrefix} ${errMsg}`);
- throw new BaseError(errMsg);
+ logger.error(`${logPrefix} ${errorMsg}`);
+ throw new BaseError(errorMsg);
}
return defaultVoltageOut;
}
return (
stationInfo.idTagsFile &&
path.join(
- path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
+ path.dirname(fileURLToPath(import.meta.url)),
'assets',
path.basename(stationInfo.idTagsFile)
)
);
}
+ private static getConfiguredNumberOfConnectors(stationTemplate: ChargingStationTemplate): number {
+ let configuredMaxConnectors: number;
+ if (Utils.isNotEmptyArray(stationTemplate.numberOfConnectors) === true) {
+ const numberOfConnectors = stationTemplate.numberOfConnectors as number[];
+ configuredMaxConnectors =
+ numberOfConnectors[Math.floor(Utils.secureRandom() * numberOfConnectors.length)];
+ } else if (Utils.isUndefined(stationTemplate.numberOfConnectors) === false) {
+ configuredMaxConnectors = stationTemplate.numberOfConnectors as number;
+ } else if (stationTemplate.Connectors && !stationTemplate.Evses) {
+ configuredMaxConnectors = stationTemplate?.Connectors[0]
+ ? ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors) - 1
+ : ChargingStationUtils.getMaxNumberOfConnectors(stationTemplate.Connectors);
+ } else if (stationTemplate.Evses && !stationTemplate.Connectors) {
+ configuredMaxConnectors = 0;
+ for (const evse in stationTemplate.Evses) {
+ if (evse === '0') {
+ continue;
+ }
+ configuredMaxConnectors += ChargingStationUtils.getMaxNumberOfConnectors(
+ stationTemplate.Evses[evse].Connectors
+ );
+ }
+ }
+ return configuredMaxConnectors;
+ }
+
+ private static checkConfiguredMaxConnectors(
+ configuredMaxConnectors: number,
+ logPrefix: string,
+ templateFile: string
+ ): void {
+ if (configuredMaxConnectors <= 0) {
+ logger.warn(
+ `${logPrefix} Charging station information from template ${templateFile} with ${configuredMaxConnectors} connectors`
+ );
+ }
+ }
+
+ private static checkTemplateMaxConnectors(
+ templateMaxConnectors: number,
+ logPrefix: string,
+ templateFile: string
+ ): void {
+ if (templateMaxConnectors === 0) {
+ logger.warn(
+ `${logPrefix} Charging station information from template ${templateFile} with empty connectors configuration`
+ );
+ } else if (templateMaxConnectors < 0) {
+ logger.error(
+ `${logPrefix} Charging station information from template ${templateFile} with no connectors configuration defined`
+ );
+ }
+ }
+
private static initializeConnectorStatus(connectorStatus: ConnectorStatus): void {
connectorStatus.availability = AvailabilityType.Operative;
connectorStatus.idTagLocalAuthorized = false;
private static warnDeprecatedTemplateKey(
template: ChargingStationTemplate,
key: string,
- templateFile: string,
logPrefix: string,
+ templateFile: string,
logMsgToAppend = ''
): void {
if (!Utils.isUndefined(template[key])) {