// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import fs from 'fs';
import crypto from 'node:crypto';
-import path from 'path';
-import { URL } from 'url';
-import { parentPort } from 'worker_threads';
+import fs from 'node:fs';
+import path from 'node:path';
+import { URL } from 'node:url';
+import { parentPort } from 'node:worker_threads';
import merge from 'just-merge';
import WebSocket, { type RawData } from 'ws';
-import AuthorizedTagsCache from './AuthorizedTagsCache';
-import AutomaticTransactionGenerator from './AutomaticTransactionGenerator';
-import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
-import { ChargingStationUtils } from './ChargingStationUtils';
-import ChargingStationWorkerBroadcastChannel from './ChargingStationWorkerBroadcastChannel';
-import { MessageChannelUtils } from './MessageChannelUtils';
-import OCPP16IncomingRequestService from './ocpp/1.6/OCPP16IncomingRequestService';
-import OCPP16RequestService from './ocpp/1.6/OCPP16RequestService';
-import OCPP16ResponseService from './ocpp/1.6/OCPP16ResponseService';
-import { OCPP16ServiceUtils } from './ocpp/1.6/OCPP16ServiceUtils';
-import OCPP20IncomingRequestService from './ocpp/2.0/OCPP20IncomingRequestService';
-import OCPP20RequestService from './ocpp/2.0/OCPP20RequestService';
-import OCPP20ResponseService from './ocpp/2.0/OCPP20ResponseService';
-import type OCPPIncomingRequestService from './ocpp/OCPPIncomingRequestService';
-import type OCPPRequestService from './ocpp/OCPPRequestService';
-import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
-import SharedLRUCache from './SharedLRUCache';
-import BaseError from '../exception/BaseError';
-import OCPPError from '../exception/OCPPError';
-import PerformanceStatistics from '../performance/PerformanceStatistics';
-import type { AutomaticTransactionGeneratorConfiguration } from '../types/AutomaticTransactionGenerator';
-import type { ChargingStationConfiguration } from '../types/ChargingStationConfiguration';
-import type { ChargingStationInfo } from '../types/ChargingStationInfo';
-import type { ChargingStationOcppConfiguration } from '../types/ChargingStationOcppConfiguration';
import {
- type ChargingStationTemplate,
- CurrentType,
- PowerUnits,
- type WsOptions,
-} from '../types/ChargingStationTemplate';
-import { SupervisionUrlDistribution } from '../types/ConfigurationData';
-import type { ConnectorStatus } from '../types/ConnectorStatus';
-import { FileType } from '../types/FileType';
-import type { JsonType } from '../types/JsonType';
+ AuthorizedTagsCache,
+ AutomaticTransactionGenerator,
+ ChargingStationConfigurationUtils,
+ ChargingStationUtils,
+ ChargingStationWorkerBroadcastChannel,
+ MessageChannelUtils,
+ SharedLRUCache,
+} from './internal';
import {
- ConnectorPhaseRotation,
- StandardParametersKey,
- SupportedFeatureProfiles,
- VendorDefaultParametersKey,
-} from '../types/ocpp/Configuration';
-import { ConnectorStatusEnum } from '../types/ocpp/ConnectorStatusEnum';
-import { ErrorType } from '../types/ocpp/ErrorType';
-import { MessageType } from '../types/ocpp/MessageType';
-import { MeterValue, MeterValueMeasurand } from '../types/ocpp/MeterValues';
-import { OCPPVersion } from '../types/ocpp/OCPPVersion';
+ // OCPP16IncomingRequestService,
+ OCPP16RequestService,
+ // OCPP16ResponseService,
+ OCPP16ServiceUtils,
+ OCPP20IncomingRequestService,
+ OCPP20RequestService,
+ // OCPP20ResponseService,
+ type OCPPIncomingRequestService,
+ type OCPPRequestService,
+ // OCPPServiceUtils,
+} from './ocpp';
+import { OCPP16IncomingRequestService } from './ocpp/1.6/OCPP16IncomingRequestService';
+import { OCPP16ResponseService } from './ocpp/1.6/OCPP16ResponseService';
+import { OCPP20ResponseService } from './ocpp/2.0/OCPP20ResponseService';
+import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
+import { BaseError, OCPPError } from '../exception';
+import { PerformanceStatistics } from '../performance';
import {
+ type AutomaticTransactionGeneratorConfiguration,
AvailabilityType,
type BootNotificationRequest,
+ type BootNotificationResponse,
type CachedRequest,
+ type ChargingStationConfiguration,
+ type ChargingStationInfo,
+ type ChargingStationOcppConfiguration,
+ type ChargingStationTemplate,
+ ConnectorPhaseRotation,
+ ConnectorStatus,
+ ConnectorStatusEnum,
+ CurrentType,
type ErrorCallback,
+ type ErrorResponse,
+ ErrorType,
+ FileType,
FirmwareStatus,
type FirmwareStatusNotificationRequest,
+ type FirmwareStatusNotificationResponse,
+ type FirmwareUpgrade,
type HeartbeatRequest,
+ type HeartbeatResponse,
type IncomingRequest,
- IncomingRequestCommand,
+ type IncomingRequestCommand,
+ type JsonType,
+ MessageType,
+ type MeterValue,
+ MeterValueMeasurand,
type MeterValuesRequest,
+ type MeterValuesResponse,
+ OCPPVersion,
type OutgoingRequest,
+ PowerUnits,
+ RegistrationStatusEnumType,
RequestCommand,
+ type Response,
type ResponseCallback,
+ StandardParametersKey,
type StatusNotificationRequest,
-} from '../types/ocpp/Requests';
-import {
- type BootNotificationResponse,
- type ErrorResponse,
- type FirmwareStatusNotificationResponse,
- type HeartbeatResponse,
- type MeterValuesResponse,
- RegistrationStatusEnumType,
- type Response,
type StatusNotificationResponse,
-} from '../types/ocpp/Responses';
-import {
StopTransactionReason,
type StopTransactionRequest,
type StopTransactionResponse,
-} from '../types/ocpp/Transaction';
-import { WSError, WebSocketCloseEventStatusCode } from '../types/WebSocket';
-import Configuration from '../utils/Configuration';
-import Constants from '../utils/Constants';
-import { ACElectricUtils, DCElectricUtils } from '../utils/ElectricUtils';
-import FileUtils from '../utils/FileUtils';
-import logger from '../utils/Logger';
-import Utils from '../utils/Utils';
-
-export default class ChargingStation {
+ SupervisionUrlDistribution,
+ SupportedFeatureProfiles,
+ VendorParametersKey,
+ type WSError,
+ WebSocketCloseEventStatusCode,
+ type WsOptions,
+} from '../types';
+import {
+ ACElectricUtils,
+ Configuration,
+ Constants,
+ DCElectricUtils,
+ FileUtils,
+ Utils,
+ logger,
+} from '../utils';
+
+export class ChargingStation {
public readonly index: number;
public readonly templateFile: string;
public stationInfo!: ChargingStationInfo;
public started: boolean;
public starting: boolean;
public authorizedTagsCache: AuthorizedTagsCache;
- public automaticTransactionGenerator!: AutomaticTransactionGenerator;
- public ocppConfiguration!: ChargingStationOcppConfiguration;
- public wsConnection!: WebSocket;
+ public automaticTransactionGenerator!: AutomaticTransactionGenerator | undefined;
+ public ocppConfiguration!: ChargingStationOcppConfiguration | undefined;
+ public wsConnection!: WebSocket | null;
public readonly connectors: Map<number, ConnectorStatus>;
public readonly requests: Map<string, CachedRequest>;
- public performanceStatistics!: PerformanceStatistics;
+ public performanceStatistics!: PerformanceStatistics | undefined;
public heartbeatSetInterval!: NodeJS.Timeout;
public ocppRequestService!: OCPPRequestService;
public bootNotificationRequest!: BootNotificationRequest;
private configuredSupervisionUrlIndex!: number;
private wsConnectionRestarted: boolean;
private autoReconnectRetryCount: number;
- private templateFileWatcher!: fs.FSWatcher;
+ private templateFileWatcher!: fs.FSWatcher | undefined;
private readonly sharedLRUCache: SharedLRUCache;
private webSocketPingSetInterval!: NodeJS.Timeout;
private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel;
? ChargingStationConfigurationUtils.getConfigurationKey(
this,
this.getSupervisionUrlOcppKey()
- ).value
+ )?.value
: this.configuredSupervisionUrl.href
}/${this.stationInfo.chargingStationId}`
);
}
- public logPrefix(): string {
+ public logPrefix = (): string => {
return Utils.logPrefix(
` ${
- this?.stationInfo?.chargingStationId ??
- ChargingStationUtils.getChargingStationId(this.index, this.getTemplateFromFile())
+ (Utils.isNotEmptyString(this?.stationInfo?.chargingStationId) &&
+ this?.stationInfo?.chargingStationId) ??
+ ChargingStationUtils.getChargingStationId(this.index, this.getTemplateFromFile()) ??
+ ''
} |`
);
- }
+ };
public hasAuthorizedTags(): boolean {
- return !Utils.isEmptyArray(
+ return Utils.isNotEmptyArray(
this.authorizedTagsCache.getAuthorizedTags(
ChargingStationUtils.getAuthorizationFile(this.stationInfo)
)
}
public getCurrentOutType(stationInfo?: ChargingStationInfo): CurrentType {
- return (stationInfo ?? this.stationInfo).currentOutType ?? CurrentType.AC;
+ return (stationInfo ?? this.stationInfo)?.currentOutType ?? CurrentType.AC;
}
public getOcppStrictCompliance(): boolean {
let connectorAmperageLimitationPowerLimit: number;
if (
!Utils.isNullOrUndefined(this.getAmperageLimitation()) &&
- this.getAmperageLimitation() < this.stationInfo.maximumAmperage
+ this.getAmperageLimitation() < this.stationInfo?.maximumAmperage
) {
connectorAmperageLimitationPowerLimit =
(this.getCurrentOutType() === CurrentType.AC
connectorId > 0 &&
this.getConnectorStatus(connectorId)?.transactionId === transactionId
) {
- return this.getConnectorStatus(connectorId).transactionIdTag;
+ return this.getConnectorStatus(connectorId)?.transactionIdTag;
}
}
}
this.heartbeatSetInterval = setInterval(() => {
this.ocppRequestService
.requestHandler<HeartbeatRequest, HeartbeatResponse>(this, RequestCommand.HEARTBEAT)
- .catch(error => {
+ .catch((error) => {
logger.error(
`${this.logPrefix()} Error while sending '${RequestCommand.HEARTBEAT}':`,
error
return;
} else if (
this.getConnectorStatus(connectorId)?.transactionStarted === true &&
- !this.getConnectorStatus(connectorId)?.transactionId
+ Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionId)
) {
logger.error(
`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction id`
RequestCommand.METER_VALUES,
{
connectorId,
- transactionId: this.getConnectorStatus(connectorId).transactionId,
+ transactionId: this.getConnectorStatus(connectorId)?.transactionId,
meterValue: [meterValue],
}
)
- .catch(error => {
+ .catch((error) => {
logger.error(
`${this.logPrefix()} Error while sending '${RequestCommand.METER_VALUES}':`,
error
if (this.starting === false) {
this.starting = true;
if (this.getEnableStatistics() === true) {
- this.performanceStatistics.start();
+ this.performanceStatistics?.start();
}
this.openWSConnection();
// Monitor charging station template file
this.templateFileWatcher = FileUtils.watchJsonFile(
- this.logPrefix(),
- FileType.ChargingStationTemplate,
this.templateFile,
- null,
+ FileType.ChargingStationTemplate,
+ this.logPrefix(),
+ undefined,
(event, filename): void => {
- if (filename && event === 'change') {
+ if (Utils.isNotEmptyString(filename) && event === 'change') {
try {
logger.debug(
`${this.logPrefix()} ${FileType.ChargingStationTemplate} ${
this.startAutomaticTransactionGenerator();
}
if (this.getEnableStatistics() === true) {
- this.performanceStatistics.restart();
+ this.performanceStatistics?.restart();
} else {
- this.performanceStatistics.stop();
+ this.performanceStatistics?.stop();
}
// FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
} catch (error) {
await this.stopMessageSequence(reason);
this.closeWSConnection();
if (this.getEnableStatistics() === true) {
- this.performanceStatistics.stop();
+ this.performanceStatistics?.stop();
}
this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
- this.templateFileWatcher.close();
+ this.templateFileWatcher?.close();
this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
this.bootNotificationResponse = undefined;
this.started = false;
this.getConnectorStatus(connectorId).idTagAuthorized = false;
this.getConnectorStatus(connectorId).transactionRemoteStarted = false;
this.getConnectorStatus(connectorId).transactionStarted = false;
- delete this.getConnectorStatus(connectorId).localAuthorizeIdTag;
- delete this.getConnectorStatus(connectorId).authorizeIdTag;
- delete this.getConnectorStatus(connectorId).transactionId;
- delete this.getConnectorStatus(connectorId).transactionIdTag;
+ delete this.getConnectorStatus(connectorId)?.localAuthorizeIdTag;
+ delete this.getConnectorStatus(connectorId)?.authorizeIdTag;
+ delete this.getConnectorStatus(connectorId)?.transactionId;
+ delete this.getConnectorStatus(connectorId)?.transactionIdTag;
this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
- delete this.getConnectorStatus(connectorId).transactionBeginMeterValue;
+ delete this.getConnectorStatus(connectorId)?.transactionBeginMeterValue;
this.stopMeterValues(connectorId);
parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
}
- public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean {
+ public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean | undefined {
return ChargingStationConfigurationUtils.getConfigurationKey(
this,
StandardParametersKey.SupportedFeatureProfiles
- )?.value.includes(featureProfile);
+ )?.value?.includes(featureProfile);
}
public bufferMessage(message: string): void {
public closeWSConnection(): void {
if (this.isWebSocketConnectionOpened() === true) {
- this.wsConnection.close();
+ this.wsConnection?.close();
this.wsConnection = null;
}
}
this.getAutomaticTransactionGeneratorConfigurationFromTemplate(),
this
);
- if (!Utils.isEmptyArray(connectorIds)) {
+ if (Utils.isNotEmptyArray(connectorIds)) {
for (const connectorId of connectorIds) {
- this.automaticTransactionGenerator.startConnector(connectorId);
+ this.automaticTransactionGenerator?.startConnector(connectorId);
}
} else {
- this.automaticTransactionGenerator.start();
+ this.automaticTransactionGenerator?.start();
}
parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
}
public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
- if (!Utils.isEmptyArray(connectorIds)) {
+ if (Utils.isNotEmptyArray(connectorIds)) {
for (const connectorId of connectorIds) {
this.automaticTransactionGenerator?.stopConnector(connectorId);
}
connectorId: number,
reason = StopTransactionReason.NONE
): Promise<StopTransactionResponse> {
- const transactionId = this.getConnectorStatus(connectorId).transactionId;
+ const transactionId = this.getConnectorStatus(connectorId)?.transactionId;
if (
this.getBeginEndMeterValues() === true &&
this.getOcppStrictCompliance() === true &&
private flushMessageBuffer(): void {
if (this.messageBuffer.size > 0) {
- this.messageBuffer.forEach(message => {
+ this.messageBuffer.forEach((message) => {
let beginId: string;
let commandName: RequestCommand;
const [messageType] = JSON.parse(message) as OutgoingRequest | Response | ErrorResponse;
[, , commandName] = JSON.parse(message) as OutgoingRequest;
beginId = PerformanceStatistics.beginMeasure(commandName);
}
- this.wsConnection.send(message);
+ this.wsConnection?.send(message);
isRequest && PerformanceStatistics.endMeasure(commandName, beginId);
logger.debug(
`${this.logPrefix()} >> Buffered ${OCPPServiceUtils.getMessageTypeString(
}
private getSupervisionUrlOcppKey(): string {
- return this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl;
+ return this.stationInfo.supervisionUrlOcppKey ?? VendorParametersKey.ConnectionUrl;
}
- private getTemplateFromFile(): ChargingStationTemplate | null {
- let template: ChargingStationTemplate = null;
+ private getTemplateFromFile(): ChargingStationTemplate | undefined {
+ let template: ChargingStationTemplate;
try {
if (this.sharedLRUCache.hasChargingStationTemplate(this.stationInfo?.templateHash)) {
template = this.sharedLRUCache.getChargingStationTemplate(this.stationInfo.templateHash);
}
} catch (error) {
FileUtils.handleFileException(
- this.logPrefix(),
- FileType.ChargingStationTemplate,
this.templateFile,
- error as NodeJS.ErrnoException
+ FileType.ChargingStationTemplate,
+ error as NodeJS.ErrnoException,
+ this.logPrefix()
);
}
return template;
}
private getStationInfoFromTemplate(): ChargingStationInfo {
- const stationTemplate: ChargingStationTemplate = this.getTemplateFromFile();
+ const stationTemplate: ChargingStationTemplate | undefined = this.getTemplateFromFile();
if (Utils.isNullOrUndefined(stationTemplate)) {
const errorMsg = `Failed to read charging station template file ${this.templateFile}`;
logger.error(`${this.logPrefix()} ${errorMsg}`);
this.index,
stationTemplate
);
- stationInfo.ocppVersion = stationTemplate.ocppVersion ?? OCPPVersion.VERSION_16;
+ stationInfo.ocppVersion = stationTemplate?.ocppVersion ?? OCPPVersion.VERSION_16;
ChargingStationUtils.createSerialNumber(stationTemplate, stationInfo);
- if (!Utils.isEmptyArray(stationTemplate.power)) {
+ if (Utils.isNotEmptyArray(stationTemplate?.power)) {
stationTemplate.power = stationTemplate.power as number[];
const powerArrayRandomIndex = Math.floor(Utils.secureRandom() * stationTemplate.power.length);
stationInfo.maximumPower =
- stationTemplate.powerUnit === PowerUnits.KILO_WATT
+ stationTemplate?.powerUnit === PowerUnits.KILO_WATT
? stationTemplate.power[powerArrayRandomIndex] * 1000
: stationTemplate.power[powerArrayRandomIndex];
} else {
- stationTemplate.power = stationTemplate.power as number;
+ stationTemplate.power = stationTemplate?.power as number;
stationInfo.maximumPower =
- stationTemplate.powerUnit === PowerUnits.KILO_WATT
+ stationTemplate?.powerUnit === PowerUnits.KILO_WATT
? stationTemplate.power * 1000
: stationTemplate.power;
}
stationInfo.firmwareVersionPattern =
- stationTemplate.firmwareVersionPattern ?? Constants.SEMVER_PATTERN;
+ stationTemplate?.firmwareVersionPattern ?? Constants.SEMVER_PATTERN;
if (
- stationInfo.firmwareVersion &&
+ Utils.isNotEmptyString(stationInfo.firmwareVersion) &&
new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion) === false
) {
logger.warn(
} does not match firmware version pattern '${stationInfo.firmwareVersionPattern}'`
);
}
- stationInfo.firmwareUpgrade = merge(
+ stationInfo.firmwareUpgrade = merge<FirmwareUpgrade>(
{
+ versionUpgrade: {
+ step: 1,
+ },
reset: true,
},
- stationTemplate.firmwareUpgrade ?? {}
+ stationTemplate?.firmwareUpgrade ?? {}
);
- stationInfo.resetTime = stationTemplate.resetTime
+ stationInfo.resetTime = !Utils.isNullOrUndefined(stationTemplate?.resetTime)
? stationTemplate.resetTime * 1000
: Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
const configuredMaxConnectors =
return stationInfo;
}
- private getStationInfoFromFile(): ChargingStationInfo | null {
- let stationInfo: ChargingStationInfo = null;
+ private getStationInfoFromFile(): ChargingStationInfo | undefined {
+ let stationInfo: ChargingStationInfo | undefined;
this.getStationInfoPersistentConfiguration() &&
- (stationInfo = this.getConfigurationFromFile()?.stationInfo ?? null);
+ (stationInfo = this.getConfigurationFromFile()?.stationInfo);
stationInfo && ChargingStationUtils.createStationInfoHash(stationInfo);
return stationInfo;
}
private getStationInfo(): ChargingStationInfo {
const stationInfoFromTemplate: ChargingStationInfo = this.getStationInfoFromTemplate();
- const stationInfoFromFile: ChargingStationInfo = this.getStationInfoFromFile();
+ const stationInfoFromFile: ChargingStationInfo | undefined = this.getStationInfoFromFile();
// Priority: charging station info from template > charging station info from configuration file > charging station info attribute
if (stationInfoFromFile?.templateHash === stationInfoFromTemplate.templateHash) {
if (this.stationInfo?.infoHash === stationInfoFromFile?.infoHash) {
}
if (
this.stationInfo.firmwareStatus === FirmwareStatus.Installing &&
- this.stationInfo.firmwareVersion &&
- this.stationInfo.firmwareVersionPattern
+ Utils.isNotEmptyString(this.stationInfo.firmwareVersion) &&
+ Utils.isNotEmptyString(this.stationInfo.firmwareVersionPattern)
) {
- const versionStep = this.stationInfo.firmwareUpgrade?.versionUpgrade?.step ?? 1;
- const patternGroup: number =
+ const patternGroup: number | undefined =
this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
- this.stationInfo.firmwareVersion.split('.').length;
- const match = this.stationInfo.firmwareVersion
- .match(new RegExp(this.stationInfo.firmwareVersionPattern))
- .slice(1, patternGroup + 1);
+ this.stationInfo.firmwareVersion?.split('.').length;
+ const match = this.stationInfo?.firmwareVersion
+ ?.match(new RegExp(this.stationInfo.firmwareVersionPattern))
+ ?.slice(1, patternGroup + 1);
const patchLevelIndex = match.length - 1;
match[patchLevelIndex] = (
- Utils.convertToInt(match[patchLevelIndex]) + versionStep
+ Utils.convertToInt(match[patchLevelIndex]) +
+ this.stationInfo.firmwareUpgrade?.versionUpgrade?.step
).toString();
- this.stationInfo.firmwareVersion = match.join('.');
+ this.stationInfo.firmwareVersion = match?.join('.');
}
}
);
}
if (
- this.stationInfo.amperageLimitationOcppKey &&
+ Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
!ChargingStationConfigurationUtils.getConfigurationKey(
this,
this.stationInfo.amperageLimitationOcppKey
ChargingStationConfigurationUtils.getConfigurationKey(
this,
StandardParametersKey.SupportedFeatureProfiles
- )?.value.includes(SupportedFeatureProfiles.LocalAuthListManagement)
+ )?.value?.includes(SupportedFeatureProfiles.LocalAuthListManagement)
) {
ChargingStationConfigurationUtils.addConfigurationKey(
this,
}
// Initialize transaction attributes on connectors
for (const connectorId of this.connectors.keys()) {
- if (connectorId > 0 && this.getConnectorStatus(connectorId).transactionStarted === true) {
+ if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
logger.warn(
`${this.logPrefix()} Connector ${connectorId} at initialization has a transaction started: ${
- this.getConnectorStatus(connectorId).transactionId
+ this.getConnectorStatus(connectorId)?.transactionId
}`
);
}
if (
connectorId > 0 &&
- (this.getConnectorStatus(connectorId).transactionStarted === undefined ||
- this.getConnectorStatus(connectorId).transactionStarted === null)
+ (this.getConnectorStatus(connectorId)?.transactionStarted === undefined ||
+ this.getConnectorStatus(connectorId)?.transactionStarted === null)
) {
this.initializeConnectorStatus(connectorId);
}
}
}
- private getConfigurationFromFile(): ChargingStationConfiguration | null {
- let configuration: ChargingStationConfiguration = null;
+ private getConfigurationFromFile(): ChargingStationConfiguration | undefined {
+ let configuration: ChargingStationConfiguration | undefined;
if (this.configurationFile && fs.existsSync(this.configurationFile)) {
try {
if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) {
}
} catch (error) {
FileUtils.handleFileException(
- this.logPrefix(),
- FileType.ChargingStationConfiguration,
this.configurationFile,
- error as NodeJS.ErrnoException
+ FileType.ChargingStationConfiguration,
+ error as NodeJS.ErrnoException,
+ this.logPrefix()
);
}
}
fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
}
const configurationData: ChargingStationConfiguration =
- this.getConfigurationFromFile() ?? {};
+ Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
this.ocppConfiguration?.configurationKey &&
(configurationData.configurationKey = this.ocppConfiguration.configurationKey);
this.stationInfo && (configurationData.stationInfo = this.stationInfo);
}
} catch (error) {
FileUtils.handleFileException(
- this.logPrefix(),
- FileType.ChargingStationConfiguration,
this.configurationFile,
- error as NodeJS.ErrnoException
+ FileType.ChargingStationConfiguration,
+ error as NodeJS.ErrnoException,
+ this.logPrefix()
);
}
} else {
}
}
- private getOcppConfigurationFromTemplate(): ChargingStationOcppConfiguration | null {
- return this.getTemplateFromFile()?.Configuration ?? null;
+ private getOcppConfigurationFromTemplate(): ChargingStationOcppConfiguration | undefined {
+ return this.getTemplateFromFile()?.Configuration;
}
- private getOcppConfigurationFromFile(): ChargingStationOcppConfiguration | null {
- let configuration: ChargingStationConfiguration = null;
+ private getOcppConfigurationFromFile(): ChargingStationOcppConfiguration | undefined {
+ let configuration: ChargingStationConfiguration | undefined;
if (this.getOcppPersistentConfiguration() === true) {
const configurationFromFile = this.getConfigurationFromFile();
configuration = configurationFromFile?.configurationKey && configurationFromFile;
}
- configuration && delete configuration.stationInfo;
+ if (!Utils.isNullOrUndefined(configuration)) {
+ delete configuration.stationInfo;
+ delete configuration.configurationHash;
+ }
return configuration;
}
- private getOcppConfiguration(): ChargingStationOcppConfiguration | null {
- let ocppConfiguration: ChargingStationOcppConfiguration = this.getOcppConfigurationFromFile();
+ private getOcppConfiguration(): ChargingStationOcppConfiguration | undefined {
+ let ocppConfiguration: ChargingStationOcppConfiguration | undefined =
+ this.getOcppConfigurationFromFile();
if (!ocppConfiguration) {
ocppConfiguration = this.getOcppConfigurationFromTemplate();
}
case MessageType.CALL_MESSAGE:
[, , commandName, commandPayload] = request as IncomingRequest;
if (this.getEnableStatistics() === true) {
- this.performanceStatistics.addRequestStatistic(commandName, messageType);
+ this.performanceStatistics?.addRequestStatistic(commandName, messageType);
}
logger.debug(
`${this.logPrefix()} << Command '${commandName}' received request payload: ${JSON.stringify(
throw new OCPPError(
ErrorType.INTERNAL_ERROR,
`Response for unknown message id ${messageId}`,
- null,
+ undefined,
commandPayload
);
}
throw new OCPPError(
ErrorType.PROTOCOL_ERROR,
`Cached request for message id ${messageId} response is not an array`,
- null,
+ undefined,
cachedRequest as unknown as JsonType
);
}
throw new OCPPError(
ErrorType.INTERNAL_ERROR,
`Error response for unknown message id ${messageId}`,
- null,
+ undefined,
{ errorType, errorMessage, errorDetails }
);
}
throw new OCPPError(
ErrorType.PROTOCOL_ERROR,
`Cached request for message id ${messageId} error response is not an array`,
- null,
+ undefined,
cachedRequest as unknown as JsonType
);
}
private getUseConnectorId0(stationInfo?: ChargingStationInfo): boolean {
const localStationInfo = stationInfo ?? this.stationInfo;
- return !Utils.isUndefined(localStationInfo.useConnectorId0)
- ? localStationInfo.useConnectorId0
- : true;
+ return localStationInfo?.useConnectorId0 ?? true;
}
private getNumberOfRunningTransactions(): number {
}
// -1 for unlimited, 0 for disabling
- private getAutoReconnectMaxRetries(): number {
+ private getAutoReconnectMaxRetries(): number | undefined {
if (!Utils.isUndefined(this.stationInfo.autoReconnectMaxRetries)) {
return this.stationInfo.autoReconnectMaxRetries;
}
}
// 0 for disabling
- private getRegistrationMaxRetries(): number {
+ private getRegistrationMaxRetries(): number | undefined {
if (!Utils.isUndefined(this.stationInfo.registrationMaxRetries)) {
return this.stationInfo.registrationMaxRetries;
}
private getAmperageLimitation(): number | undefined {
if (
- this.stationInfo.amperageLimitationOcppKey &&
+ Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
ChargingStationConfigurationUtils.getConfigurationKey(
this,
this.stationInfo.amperageLimitationOcppKey
ChargingStationConfigurationUtils.getConfigurationKey(
this,
this.stationInfo.amperageLimitationOcppKey
- ).value
+ )?.value
) / ChargingStationUtils.getAmperageLimitationUnitDivider(this.stationInfo)
);
}
this.startHeartbeat();
// Initialize connectors status
for (const connectorId of this.connectors.keys()) {
- let connectorStatus: ConnectorStatusEnum;
+ let connectorStatus: ConnectorStatusEnum | undefined;
if (connectorId === 0) {
continue;
} else if (
this.getConnectorStatus(connectorId)?.bootStatus
) {
// Set boot status in template at startup
- connectorStatus = this.getConnectorStatus(connectorId).bootStatus;
+ connectorStatus = this.getConnectorStatus(connectorId)?.bootStatus;
} else if (this.getConnectorStatus(connectorId)?.status) {
// Set previous status at startup
- connectorStatus = this.getConnectorStatus(connectorId).status;
+ connectorStatus = this.getConnectorStatus(connectorId)?.status;
} else {
// Set default status
connectorStatus = ConnectorStatusEnum.AVAILABLE;
ConnectorStatusEnum.UNAVAILABLE
)
);
- this.getConnectorStatus(connectorId).status = null;
+ this.getConnectorStatus(connectorId).status = undefined;
}
}
}
ChargingStationConfigurationUtils.getConfigurationKey(
this,
StandardParametersKey.WebSocketPingInterval
- ).value
+ )?.value
)
: 0;
if (webSocketPingInterval > 0 && !this.webSocketPingSetInterval) {
this.webSocketPingSetInterval = setInterval(() => {
if (this.isWebSocketConnectionOpened() === true) {
- this.wsConnection.ping();
+ this.wsConnection?.ping();
}
}, webSocketPingInterval * 1000);
logger.info(
}
private getConfiguredSupervisionUrl(): URL {
- const supervisionUrls = this.stationInfo.supervisionUrls ?? Configuration.getSupervisionUrls();
- if (!Utils.isEmptyArray(supervisionUrls)) {
+ const supervisionUrls = this.stationInfo?.supervisionUrls ?? Configuration.getSupervisionUrls();
+ if (Utils.isNotEmptyArray(supervisionUrls)) {
switch (Configuration.getSupervisionUrlDistribution()) {
case SupervisionUrlDistribution.ROUND_ROBIN:
// FIXME
private terminateWSConnection(): void {
if (this.isWebSocketConnectionOpened() === true) {
- this.wsConnection.terminate();
+ this.wsConnection?.terminate();
this.wsConnection = null;
}
}
private stopMeterValues(connectorId: number) {
if (this.getConnectorStatus(connectorId)?.transactionSetInterval) {
- clearInterval(this.getConnectorStatus(connectorId).transactionSetInterval);
+ clearInterval(this.getConnectorStatus(connectorId)?.transactionSetInterval);
}
}
private getReconnectExponentialDelay(): boolean {
- return !Utils.isUndefined(this.stationInfo.reconnectExponentialDelay)
- ? this.stationInfo.reconnectExponentialDelay
- : false;
+ return this.stationInfo?.reconnectExponentialDelay ?? false;
}
private async reconnect(): Promise<void> {
}
}
- private getAutomaticTransactionGeneratorConfigurationFromTemplate(): AutomaticTransactionGeneratorConfiguration | null {
- return this.getTemplateFromFile()?.AutomaticTransactionGenerator ?? null;
+ private getAutomaticTransactionGeneratorConfigurationFromTemplate():
+ | AutomaticTransactionGeneratorConfiguration
+ | undefined {
+ return this.getTemplateFromFile()?.AutomaticTransactionGenerator;
}
private initializeConnectorStatus(connectorId: number): void {