X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=23724e79014584cdf9d5dc042cd29b0fcce0f249;hb=1185579a331f3484e8ed7882203d2e58466635dd;hp=79cf45b8a60166c3caa9cef671f921031956142d;hpb=1b271a549cfd1b8e678a56918f113ebc7c17f592;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 79cf45b8..23724e79 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -4,96 +4,101 @@ import crypto from 'node:crypto'; import fs from 'node:fs'; import path from 'node:path'; import { URL } from 'node:url'; -import { parentPort } from 'worker_threads'; +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; @@ -160,7 +165,7 @@ export default class ChargingStation { public logPrefix = (): string => { return Utils.logPrefix( ` ${ - (!Utils.isEmptyString(this?.stationInfo?.chargingStationId) && + (Utils.isNotEmptyString(this?.stationInfo?.chargingStationId) && this?.stationInfo?.chargingStationId) ?? ChargingStationUtils.getChargingStationId(this.index, this.getTemplateFromFile()) ?? '' @@ -169,7 +174,7 @@ export default class ChargingStation { }; public hasAuthorizedTags(): boolean { - return !Utils.isEmptyArray( + return Utils.isNotEmptyArray( this.authorizedTagsCache.getAuthorizedTags( ChargingStationUtils.getAuthorizationFile(this.stationInfo) ) @@ -513,7 +518,7 @@ export default class ChargingStation { this.logPrefix(), undefined, (event, filename): void => { - if (!Utils.isEmptyString(filename) && event === 'change') { + if (Utils.isNotEmptyString(filename) && event === 'change') { try { logger.debug( `${this.logPrefix()} ${FileType.ChargingStationTemplate} ${ @@ -712,7 +717,7 @@ export default class ChargingStation { this.getAutomaticTransactionGeneratorConfigurationFromTemplate(), this ); - if (!Utils.isEmptyArray(connectorIds)) { + if (Utils.isNotEmptyArray(connectorIds)) { for (const connectorId of connectorIds) { this.automaticTransactionGenerator?.startConnector(connectorId); } @@ -723,7 +728,7 @@ export default class ChargingStation { } public stopAutomaticTransactionGenerator(connectorIds?: number[]): void { - if (!Utils.isEmptyArray(connectorIds)) { + if (Utils.isNotEmptyArray(connectorIds)) { for (const connectorId of connectorIds) { this.automaticTransactionGenerator?.stopConnector(connectorId); } @@ -798,7 +803,7 @@ export default class ChargingStation { } private getSupervisionUrlOcppKey(): string { - return this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl; + return this.stationInfo.supervisionUrlOcppKey ?? VendorParametersKey.ConnectionUrl; } private getTemplateFromFile(): ChargingStationTemplate | undefined { @@ -864,7 +869,7 @@ export default class ChargingStation { ); 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 = @@ -881,7 +886,7 @@ export default class ChargingStation { stationInfo.firmwareVersionPattern = stationTemplate?.firmwareVersionPattern ?? Constants.SEMVER_PATTERN; if ( - !Utils.isEmptyString(stationInfo.firmwareVersion) && + Utils.isNotEmptyString(stationInfo.firmwareVersion) && new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion) === false ) { logger.warn( @@ -890,8 +895,11 @@ export default class ChargingStation { } does not match firmware version pattern '${stationInfo.firmwareVersionPattern}'` ); } - stationInfo.firmwareUpgrade = merge( + stationInfo.firmwareUpgrade = merge( { + versionUpgrade: { + step: 1, + }, reset: true, }, stationTemplate?.firmwareUpgrade ?? {} @@ -1033,10 +1041,9 @@ export default class ChargingStation { } if ( this.stationInfo.firmwareStatus === FirmwareStatus.Installing && - !Utils.isEmptyString(this.stationInfo.firmwareVersion) && - !Utils.isEmptyString(this.stationInfo.firmwareVersionPattern) + Utils.isNotEmptyString(this.stationInfo.firmwareVersion) && + Utils.isNotEmptyString(this.stationInfo.firmwareVersionPattern) ) { - const versionStep = this.stationInfo.firmwareUpgrade?.versionUpgrade?.step ?? 1; const patternGroup: number | undefined = this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ?? this.stationInfo.firmwareVersion?.split('.').length; @@ -1045,7 +1052,8 @@ export default class ChargingStation { ?.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('.'); } @@ -1098,7 +1106,7 @@ export default class ChargingStation { ); } if ( - !Utils.isEmptyString(this.stationInfo?.amperageLimitationOcppKey) && + Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) && !ChargingStationConfigurationUtils.getConfigurationKey( this, this.stationInfo.amperageLimitationOcppKey @@ -1354,7 +1362,7 @@ export default class ChargingStation { 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); @@ -1406,7 +1414,10 @@ export default class ChargingStation { const configurationFromFile = this.getConfigurationFromFile(); configuration = configurationFromFile?.configurationKey && configurationFromFile; } - configuration && delete configuration.stationInfo; + if (!Utils.isNullOrUndefined(configuration)) { + delete configuration.stationInfo; + delete configuration.configurationHash; + } return configuration; } @@ -1763,7 +1774,7 @@ export default class ChargingStation { private getAmperageLimitation(): number | undefined { if ( - !Utils.isEmptyString(this.stationInfo?.amperageLimitationOcppKey) && + Utils.isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) && ChargingStationConfigurationUtils.getConfigurationKey( this, this.stationInfo.amperageLimitationOcppKey @@ -1924,7 +1935,7 @@ export default class ChargingStation { private getConfiguredSupervisionUrl(): URL { const supervisionUrls = this.stationInfo?.supervisionUrls ?? Configuration.getSupervisionUrls(); - if (!Utils.isEmptyArray(supervisionUrls)) { + if (Utils.isNotEmptyArray(supervisionUrls)) { switch (Configuration.getSupervisionUrlDistribution()) { case SupervisionUrlDistribution.ROUND_ROBIN: // FIXME