X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=4ed4e600a9cd412e5f4335b648481d71a605b8a9;hb=df637b0d406ee9e6f158ee0c7c4caed7ac25ecbb;hp=63574b5c617ed3915bf7e4bdfe6fbc9edcf1d8bf;hpb=7369e417367e4cc49fe81afb15cfe47eadca9459;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 63574b5c..4ed4e600 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -3,7 +3,7 @@ import crypto from 'crypto'; import fs from 'fs'; import path from 'path'; -import { URL, fileURLToPath } from 'url'; +import { URL } from 'url'; import { parentPort } from 'worker_threads'; import WebSocket, { Data, RawData } from 'ws'; @@ -20,7 +20,6 @@ import ChargingStationTemplate, { PowerUnits, WsOptions, } from '../types/ChargingStationTemplate'; -import { ChargingStationWorkerMessageEvents } from '../types/ChargingStationWorker'; import { SupervisionUrlDistribution } from '../types/ConfigurationData'; import { ConnectorStatus } from '../types/ConnectorStatus'; import { FileType } from '../types/FileType'; @@ -74,6 +73,8 @@ 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'; @@ -87,6 +88,7 @@ export default class ChargingStation { public readonly templateFile: string; public authorizedTagsCache: AuthorizedTagsCache; public stationInfo!: ChargingStationInfo; + public stopped: boolean; public readonly connectors: Map; public ocppConfiguration!: ChargingStationOcppConfiguration; public wsConnection!: WebSocket; @@ -106,11 +108,11 @@ export default class ChargingStation { private configuredSupervisionUrl!: URL; private wsConnectionRestarted: boolean; private autoReconnectRetryCount: number; - private stopped: boolean; private templateFileWatcher!: fs.FSWatcher; private readonly sharedLRUCache: SharedLRUCache; private automaticTransactionGenerator!: AutomaticTransactionGenerator; private webSocketPingSetInterval!: NodeJS.Timeout; + private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel; constructor(index: number, templateFile: string) { this.index = index; @@ -123,6 +125,8 @@ export default class ChargingStation { this.connectors = new Map(); this.requests = new Map(); this.messageBuffer = new Set(); + this.chargingStationWorkerBroadcastChannel = new ChargingStationWorkerBroadcastChannel(this); + this.initialize(); } @@ -178,6 +182,10 @@ export default class ChargingStation { return this.stationInfo.mayAuthorizeAtRemoteStart ?? true; } + public getPayloadSchemaValidation(): boolean | undefined { + return this.stationInfo.payloadSchemaValidation ?? true; + } + public getNumberOfPhases(stationInfo?: ChargingStationInfo): number | undefined { const localStationInfo: ChargingStationInfo = stationInfo ?? this.stationInfo; switch (this.getCurrentOutType(stationInfo)) { @@ -328,22 +336,22 @@ export default class ChargingStation { } } - public getEnergyActiveImportRegisterByTransactionId(transactionId: number): number | undefined { + public getEnergyActiveImportRegisterByTransactionId(transactionId: number): number { const transactionConnectorStatus = this.getConnectorStatus( this.getConnectorIdByTransactionId(transactionId) ); if (this.getMeteringPerTransaction()) { - return transactionConnectorStatus?.transactionEnergyActiveImportRegisterValue; + return transactionConnectorStatus?.transactionEnergyActiveImportRegisterValue ?? 0; } - return transactionConnectorStatus?.energyActiveImportRegisterValue; + return transactionConnectorStatus?.energyActiveImportRegisterValue ?? 0; } - public getEnergyActiveImportRegisterByConnectorId(connectorId: number): number | undefined { + public getEnergyActiveImportRegisterByConnectorId(connectorId: number): number { const connectorStatus = this.getConnectorStatus(connectorId); if (this.getMeteringPerTransaction()) { - return connectorStatus?.transactionEnergyActiveImportRegisterValue; + return connectorStatus?.transactionEnergyActiveImportRegisterValue ?? 0; } - return connectorStatus?.energyActiveImportRegisterValue; + return connectorStatus?.energyActiveImportRegisterValue ?? 0; } public getAuthorizeRemoteTxRequests(): boolean { @@ -508,17 +516,14 @@ export default class ChargingStation { // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed } catch (error) { logger.error( - `${this.logPrefix()} ${FileType.ChargingStationTemplate} file monitoring error: %j`, + `${this.logPrefix()} ${FileType.ChargingStationTemplate} file monitoring error:`, error ); } } } ); - parentPort.postMessage({ - id: ChargingStationWorkerMessageEvents.STARTED, - data: { id: this.stationInfo.chargingStationId }, - }); + parentPort.postMessage(MessageChannelUtils.buildStartedMessage(this)); } public async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise { @@ -545,10 +550,7 @@ export default class ChargingStation { this.templateFileWatcher.close(); this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash); this.bootNotificationResponse = null; - parentPort.postMessage({ - id: ChargingStationWorkerMessageEvents.STOPPED, - data: { id: this.stationInfo.chargingStationId }, - }); + parentPort.postMessage(MessageChannelUtils.buildStoppedMessage(this)); this.stopped = true; } @@ -861,9 +863,7 @@ export default class ChargingStation { this.hashId = ChargingStationUtils.getHashId(this.index, this.getTemplateFromFile()); logger.info(`${this.logPrefix()} Charging station hashId '${this.hashId}'`); this.configurationFile = path.join( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'), - 'assets', - 'configurations', + path.dirname(this.templateFile.replace('station-templates', 'configurations')), this.hashId + '.json' ); this.stationInfo = this.getStationInfo(); @@ -1442,6 +1442,7 @@ export default class ChargingStation { logger.error(errMsg); throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg); } + parentPort.postMessage(MessageChannelUtils.buildUpdatedMessage(this)); } else { throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not iterable', null, { payload: request, @@ -1450,12 +1451,22 @@ export default class ChargingStation { } catch (error) { // Log logger.error( - '%s Incoming OCPP message %j matching cached request %j processing error %j', + "%s Incoming OCPP '%s' message '%j' matching cached request '%j' processing error:", this.logPrefix(), + commandName ?? requestCommandName ?? null, data.toString(), this.requests.get(messageId), error ); + if (!(error instanceof OCPPError)) { + logger.warn( + "%s Error thrown at incoming OCPP '%s' message '%j' handling is not an OCPPError:", + this.logPrefix(), + commandName ?? requestCommandName ?? null, + data.toString(), + error + ); + } // Send error messageType === MessageType.CALL_MESSAGE && (await this.ocppRequestService.sendError( @@ -1477,7 +1488,7 @@ export default class ChargingStation { private onError(error: WSError): void { this.closeWSConnection(); - logger.error(this.logPrefix() + ' WebSocket error: %j', error); + logger.error(this.logPrefix() + ' WebSocket error:', error); } private getUseConnectorId0(stationInfo?: ChargingStationInfo): boolean | undefined {