import { createHash } from 'node:crypto'
import { EventEmitter } from 'node:events'
-import { type FSWatcher, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
+import { type FSWatcher, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { dirname, join, parse } from 'node:path'
import { URL } from 'node:url'
import { parentPort } from 'node:worker_threads'
buildAddedMessage,
buildChargingStationAutomaticTransactionGeneratorConfiguration,
buildConnectorsStatus,
+ buildDeletedMessage,
buildEvsesStatus,
buildStartedMessage,
buildStoppedMessage,
public readonly connectors: Map<number, ConnectorStatus>
public readonly evses: Map<number, EvseStatus>
public readonly requests: Map<string, CachedRequest>
- public performanceStatistics!: PerformanceStatistics | undefined
+ public performanceStatistics: PerformanceStatistics | undefined
public heartbeatSetInterval?: NodeJS.Timeout
public ocppRequestService!: OCPPRequestService
public bootNotificationRequest?: BootNotificationRequest
private configuredSupervisionUrl!: URL
private wsConnectionRetried: boolean
private wsConnectionRetryCount: number
- private templateFileWatcher!: FSWatcher | undefined
+ private templateFileWatcher: FSWatcher | undefined
private templateFileHash!: string
private readonly sharedLRUCache: SharedLRUCache
private wsPingSetInterval?: NodeJS.Timeout
this.on(ChargingStationEvents.added, () => {
parentPort?.postMessage(buildAddedMessage(this))
})
+ this.on(ChargingStationEvents.deleted, () => {
+ parentPort?.postMessage(buildDeletedMessage(this))
+ })
this.on(ChargingStationEvents.started, () => {
parentPort?.postMessage(buildStartedMessage(this))
})
this.emit(ChargingStationEvents.added)
}
+ public async delete (deleteConfiguration = true): Promise<void> {
+ if (this.started) {
+ await this.stop()
+ }
+ AutomaticTransactionGenerator.deleteInstance(this)
+ PerformanceStatistics.deleteInstance(this.stationInfo?.hashId)
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo!)!)
+ this.requests.clear()
+ this.connectors.clear()
+ this.evses.clear()
+ this.templateFileWatcher?.unref()
+ deleteConfiguration && rmSync(this.configurationFile, { force: true })
+ this.chargingStationWorkerBroadcastChannel.unref()
+ this.emit(ChargingStationEvents.deleted)
+ }
+
public start (): void {
if (!this.started) {
if (!this.starting) {
} file have changed, reload`
)
this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash)
- // Initialize
- this.initialize()
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo!)!)
+ // Initialize
+ this.initialize()
// Restart the ATG
const ATGStarted = this.automaticTransactionGenerator?.started
if (ATGStarted === true) {
if (this.stationInfo?.enableStatistics === true) {
this.performanceStatistics?.stop()
}
- this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash)
this.templateFileWatcher?.close()
- this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash)
delete this.bootNotificationResponse
this.started = false
this.saveConfiguration()
+ this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash)
this.emit(ChargingStationEvents.stopped)
this.stopping = false
} else {
}
const stationInfo = stationTemplateToStationInfo(stationTemplate)
stationInfo.hashId = getHashId(this.index, stationTemplate)
- stationInfo.autoStart = stationTemplate.autoStart ?? true
stationInfo.templateName = parse(this.templateFile).name
stationInfo.chargingStationId = getChargingStationId(this.index, stationTemplate)
- stationInfo.ocppVersion = stationTemplate.ocppVersion ?? OCPPVersion.VERSION_16
createSerialNumber(stationTemplate, stationInfo)
stationInfo.voltageOut = this.getVoltageOut(stationInfo)
if (isNotEmptyArray(stationTemplate.power)) {
: stationTemplate.power
}
stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo)
- stationInfo.firmwareVersionPattern =
- stationTemplate.firmwareVersionPattern ?? Constants.SEMVER_PATTERN
if (
+ isNotEmptyString(stationInfo.firmwareVersionPattern) &&
isNotEmptyString(stationInfo.firmwareVersion) &&
!new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion)
) {
},
stationTemplate.firmwareUpgrade ?? {}
)
- stationInfo.resetTime =
- stationTemplate.resetTime != null
- ? secondsToMilliseconds(stationTemplate.resetTime)
- : Constants.DEFAULT_CHARGING_STATION_RESET_TIME
+ if (stationTemplate.resetTime != null) {
+ stationInfo.resetTime = secondsToMilliseconds(stationTemplate.resetTime)
+ }
return stationInfo
}
private getStationInfoFromFile (
- stationInfoPersistentConfiguration?: boolean
+ stationInfoPersistentConfiguration: boolean | undefined = Constants.DEFAULT_STATION_INFO
+ .stationInfoPersistentConfiguration
): ChargingStationInfo | undefined {
let stationInfo: ChargingStationInfo | undefined
if (stationInfoPersistentConfiguration === true) {
if (stationInfo.templateName == null) {
stationInfo.templateName = parse(this.templateFile).name
}
- if (stationInfo.autoStart == null) {
- stationInfo.autoStart = true
- }
}
}
return stationInfo
(stationInfoFromTemplate.stationInfoPersistentConfiguration =
stationInfoPersistentConfiguration)
const stationInfoFromFile = this.getStationInfoFromFile(
- stationInfoFromTemplate.stationInfoPersistentConfiguration ?? true
+ stationInfoFromTemplate.stationInfoPersistentConfiguration
)
// Priority:
// 1. charging station info from template
this.stationInfo = this.getStationInfo(options?.persistentConfiguration)
if (options?.persistentConfiguration != null) {
this.stationInfo.ocppPersistentConfiguration = options.persistentConfiguration
- }
- if (options?.persistentConfiguration != null) {
this.stationInfo.automaticTransactionGeneratorPersistentConfiguration =
options.persistentConfiguration
}
if (options?.autoRegister != null) {
this.stationInfo.autoRegister = options.autoRegister
}
+ if (options?.enableStatistics != null) {
+ this.stationInfo.enableStatistics = options.enableStatistics
+ }
+ if (options?.ocppStrictCompliance != null) {
+ this.stationInfo.ocppStrictCompliance = options.ocppStrictCompliance
+ }
+ if (options?.stopTransactionsOnStopped != null) {
+ this.stationInfo.stopTransactionsOnStopped = options.stopTransactionsOnStopped
+ }
if (
this.stationInfo.firmwareStatus === FirmwareStatus.Installing &&
- isNotEmptyString(this.stationInfo.firmwareVersion) &&
- isNotEmptyString(this.stationInfo.firmwareVersionPattern)
+ isNotEmptyString(this.stationInfo.firmwareVersionPattern) &&
+ isNotEmptyString(this.stationInfo.firmwareVersion)
) {
const patternGroup =
this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
if (!(error instanceof OCPPError)) {
logger.warn(
`${this.logPrefix()} Error thrown at incoming OCPP command '${
- commandName ?? requestCommandName ?? Constants.UNKNOWN_COMMAND
+ commandName ?? requestCommandName ?? Constants.UNKNOWN_OCPP_COMMAND
// eslint-disable-next-line @typescript-eslint/no-base-to-string
}' message '${data.toString()}' handling is not an OCPPError:`,
error
}
logger.error(
`${this.logPrefix()} Incoming OCPP command '${
- commandName ?? requestCommandName ?? Constants.UNKNOWN_COMMAND
+ commandName ?? requestCommandName ?? Constants.UNKNOWN_OCPP_COMMAND
// eslint-disable-next-line @typescript-eslint/no-base-to-string
}' message '${data.toString()}'${
this.requests.has(messageId)
}
private getUseConnectorId0 (stationTemplate?: ChargingStationTemplate): boolean {
- return stationTemplate?.useConnectorId0 ?? true
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ return stationTemplate?.useConnectorId0 ?? Constants.DEFAULT_STATION_INFO.useConnectorId0!
}
private async stopRunningTransactions (reason?: StopTransactionReason): Promise<void> {
}
private getCurrentOutType (stationInfo?: ChargingStationInfo): CurrentType {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- return (stationInfo ?? this.stationInfo!).currentOutType ?? CurrentType.AC
+ return (
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ (stationInfo ?? this.stationInfo!).currentOutType ??
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ Constants.DEFAULT_STATION_INFO.currentOutType!
+ )
}
private getVoltageOut (stationInfo?: ChargingStationInfo): Voltage {