From: Jérôme Benoit Date: Thu, 21 Jan 2021 08:49:01 +0000 (+0100) Subject: Merge pull request #6 from LucasBrazi06/memory-optimization X-Git-Tag: v1.0.1-0~137 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=f29f53d00da5e3fb216e7b98b891bb2fc678d450;hp=5c97c3b38d4d208d335617e7d77ad702d70e68bb;p=e-mobility-charging-stations-simulator.git Merge pull request #6 from LucasBrazi06/memory-optimization --- diff --git a/.gitignore b/.gitignore index 2b4ebbd7..3a622e5d 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ Thumbs.db # MTA *.mta mta_archives/ +src/scripts/scriptConfig.json diff --git a/package-lock.json b/package-lock.json index 209b0e9a..c5dd1f86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1554,6 +1554,15 @@ "integrity": "sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4=", "dev": true }, + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1829,6 +1838,11 @@ "pako": "~1.0.5" } }, + "bson": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + }, "buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", @@ -3613,6 +3627,11 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + }, "depcheck": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-0.8.3.tgz", @@ -6995,6 +7014,12 @@ "safe-buffer": "^5.1.2" } }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -7355,6 +7380,19 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, + "mongodb": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", + "integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, "morphdom": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz", @@ -9029,7 +9067,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9391,6 +9428,22 @@ "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=", "dev": true }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + }, + "dependencies": { + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + } + } + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -9553,6 +9606,15 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -9583,8 +9645,7 @@ "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "semver-compare": { "version": "1.0.0", @@ -10001,6 +10062,15 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", diff --git a/package.json b/package.json index 67fb72c9..11c18cff 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "git:spush": "git push --recurse-submodules=on-demand" }, "dependencies": { + "mongodb": "^3.6.3", "source-map-support": "^0.5.19", "tslib": "^2.1.0", "uuid": "^8.3.2", diff --git a/src/assets/config-template.json b/src/assets/config-template.json index adfe80ef..61067bcf 100644 --- a/src/assets/config-template.json +++ b/src/assets/config-template.json @@ -6,6 +6,8 @@ "statisticsDisplayInterval": 60, "useWorkerPool": false, "workerPoolSize": 16, + "chargingStationsPerWorker": 1, + "chargingStationIdSuffix": "", "stationTemplateURLs": [ { "file": "./src/assets/station-templates/siemens.station-template.json", diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index 0b1e7e27..363605be 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -97,7 +97,7 @@ export default class AutomaticTransactionGenerator { } else { startResponse = await this.startTransaction(connectorId, this); } - if (startResponse.idTagInfo.status !== AuthorizationStatus.ACCEPTED) { + if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) { logger.info(this._logPrefix(connectorId) + ' transaction rejected'); await Utils.sleep(Constants.CHARGING_STATION_ATG_WAIT_TIME); } else { @@ -131,7 +131,14 @@ export default class AutomaticTransactionGenerator { if (self._chargingStation.hasAuthorizedTags()) { const tagId = self._chargingStation.getRandomTagId(); logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId); - return await self._chargingStation.sendStartTransaction(connectorId, tagId); + // Authorize tagId + const authorizeResponse = await self._chargingStation.sendAuthorize(tagId); + if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) { + // Start transaction + return await self._chargingStation.sendStartTransaction(connectorId, tagId); + } else { + return authorizeResponse as StartTransactionResponse; + } } logger.info(self._logPrefix(connectorId) + ' start transaction without a tagID'); return await self._chargingStation.sendStartTransaction(connectorId); diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 6870c1f7..b8ac0233 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -1,4 +1,4 @@ -import { AuthorizationStatus, StartTransactionRequest, StartTransactionResponse, StopTransactionReason, StopTransactionRequest, StopTransactionResponse } from '../types/ocpp/1.6/Transaction'; +import { AuthorizationStatus, AuthorizeRequest, AuthorizeResponse, StartTransactionRequest, StartTransactionResponse, StopTransactionReason, StopTransactionRequest, StopTransactionResponse } from '../types/ocpp/1.6/Transaction'; import { AvailabilityType, BootNotificationRequest, ChangeAvailabilityRequest, ChangeConfigurationRequest, GetConfigurationRequest, HeartbeatRequest, IncomingRequestCommand, RemoteStartTransactionRequest, RemoteStopTransactionRequest, RequestCommand, ResetRequest, SetChargingProfileRequest, StatusNotificationRequest, UnlockConnectorRequest } from '../types/ocpp/1.6/Requests'; import { BootNotificationResponse, ChangeAvailabilityResponse, ChangeConfigurationResponse, DefaultResponse, GetConfigurationResponse, HeartbeatResponse, RegistrationStatus, SetChargingProfileResponse, StatusNotificationResponse, UnlockConnectorResponse } from '../types/ocpp/1.6/RequestResponses'; import { ChargingProfile, ChargingProfilePurposeType } from '../types/ocpp/1.6/ChargingProfile'; @@ -71,7 +71,13 @@ export default class ChargingStation { } _getStationName(stationTemplate: ChargingStationTemplate): string { - return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4); + // In case of multiple instances: add instance index to charging station id + let instanceIndex = process.env.CF_INSTANCE_INDEX ? process.env.CF_INSTANCE_INDEX : 0; + instanceIndex = instanceIndex > 0 ? instanceIndex : ''; + + const idSuffix = Configuration.getChargingStationIdSuffix(); + + return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + instanceIndex + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4) + idSuffix; } _buildStationInfo(): ChargingStationInfo { @@ -521,8 +527,7 @@ export default class ChargingStation { } _startAuthorizationFileMonitoring(): void { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - fs.watchFile(this._getAuthorizationFile(), (current, previous) => { + fs.watch(this._getAuthorizationFile()).on("change", e => { try { logger.debug(this._logPrefix() + ' Authorization file ' + this._getAuthorizationFile() + ' have changed, reload'); // Initialize _authorizedTags @@ -534,16 +539,25 @@ export default class ChargingStation { } _startStationTemplateFileMonitoring(): void { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - fs.watchFile(this._stationTemplateFile, (current, previous) => { + fs.watch(this._stationTemplateFile).on("change", e => { try { logger.debug(this._logPrefix() + ' Template file ' + this._stationTemplateFile + ' have changed, reload'); // Initialize this._initialize(); + // Stop the ATG if (!this._stationInfo.AutomaticTransactionGenerator.enable && this._automaticTransactionGeneration) { this._automaticTransactionGeneration.stop().catch(() => { }); } + // Start the ATG + if (this._stationInfo.AutomaticTransactionGenerator.enable) { + if (!this._automaticTransactionGeneration) { + this._automaticTransactionGeneration = new AutomaticTransactionGenerator(this); + } + if (this._automaticTransactionGeneration.timeToStop) { + this._automaticTransactionGeneration.start(); + } + } // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed } catch (error) { logger.error(this._logPrefix() + ' Charging station template file monitoring error: %j', error); @@ -811,6 +825,17 @@ export default class ChargingStation { } } + async sendAuthorize(idTag?: string): Promise { + try { + const payload: AuthorizeRequest = { + ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG }, + }; + return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, RequestCommand.AUTHORIZE) as AuthorizeResponse; + } catch (error) { + this.handleRequestError(RequestCommand.AUTHORIZE, error); + } + } + async sendStartTransaction(connectorId: number, idTag?: string): Promise { try { const payload: StartTransactionRequest = { diff --git a/src/charging-station/StationWorker.ts b/src/charging-station/StationWorker.ts index 68c3ea24..c7bc2337 100644 --- a/src/charging-station/StationWorker.ts +++ b/src/charging-station/StationWorker.ts @@ -1,8 +1,26 @@ -import { isMainThread, workerData } from 'worker_threads'; +import { isMainThread, parentPort, workerData } from 'worker_threads'; +import Constants from '../utils/Constants'; import ChargingStation from './ChargingStation'; if (!isMainThread) { const station = new ChargingStation(workerData.index as number, workerData.templateFile as string); station.start(); + + // Listener: start new charging station from main thread + addListener(); +} + +function addListener() { + parentPort.setMaxListeners(1000); + parentPort.on("message", e => { + if (e.id === Constants.START_NEW_CHARGING_STATION) { + startChargingStation(e.workerData); + } + }); +} + +function startChargingStation(data: any) { + const station = new ChargingStation(data.index as number, data.templateFile as string); + station.start(); } diff --git a/src/charging-station/Worker.ts b/src/charging-station/Worker.ts index 57748831..fbfdf3d1 100644 --- a/src/charging-station/Worker.ts +++ b/src/charging-station/Worker.ts @@ -3,12 +3,14 @@ import { Worker, WorkerOptions } from 'worker_threads'; import Configuration from '../utils/Configuration'; import Pool from 'worker-threads-pool'; import WorkerData from '../types/WorkerData'; +import Constants from '../utils/Constants'; export default class Wrk { private _workerScript: string; private _workerData: WorkerData; private _index: number; private _concurrentWorkers: number; + private _worker: Worker; /** * Create a new `Wrk`. @@ -42,11 +44,25 @@ export default class Wrk { * @return {Promise} * @public */ - async start(): Promise { + async start(): Promise { if (Configuration.useWorkerPool()) { - return this._startWorkerWithPool(); + this._startWorkerWithPool(); + } else { + this._startWorker(); } - return this._startWorker(); + return this._worker; + } + + /** + * + * @return {Promise} + * @public + */ + async startNewChargingStation(workerData: WorkerData, numConcurrentWorkers: number): Promise { + this._workerData = workerData; + this._index = workerData.index; + this._concurrentWorkers = numConcurrentWorkers; + this._worker.postMessage({ id : Constants.START_NEW_CHARGING_STATION, workerData: workerData }); } /** @@ -62,6 +78,7 @@ export default class Wrk { } worker.once('message', resolve); worker.once('error', reject); + this._worker = worker; }); }); } @@ -81,6 +98,7 @@ export default class Wrk { reject(new Error(`Worker id ${this._index} stopped with exit code ${code}`)); } }); + this._worker = worker; }); } } @@ -92,7 +110,7 @@ class WorkerPool { private constructor() { } public static getInstance(): Pool { - if (!WorkerPool._instance) { + if (!WorkerPool._instance || (WorkerPool._instance?.size === WorkerPool.concurrentWorkers)) { WorkerPool._instance = new Pool({ max: WorkerPool.concurrentWorkers }); } return WorkerPool._instance; diff --git a/src/scripts/deleteChargingStations.ts b/src/scripts/deleteChargingStations.ts new file mode 100644 index 00000000..db07c6c1 --- /dev/null +++ b/src/scripts/deleteChargingStations.ts @@ -0,0 +1,29 @@ +var MongoClient = require('mongodb'); +var fs = require('fs'); + +// This script deletes charging stations +// Filter charging stations by id pattern + +// Use Case: ev-simulator creates thousands of charging stations, which are not longer needed. +// Delete these charging stations all at once + +// Config +var config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8')); + +// Mongo Connection and Query +if (config && config.mongoConnectionString) { + MongoClient.connect(config.mongoConnectionString, { + useUnifiedTopology: true, + useNewUrlParser: true + }, async function(err, client) { + const db = client.db('evse'); + + for await (const tenantID of config.tenantIDs) { + let response = await db.collection(tenantID + '.chargingstations').deleteMany( + { _id: {'$regex': config.idPattern} } + ); + console.log(response.deletedCount, `Charging Stations with id = %${config.idPattern}% deleted. TenantID =`, tenantID); + } + client.close(); + }); +} diff --git a/src/scripts/scriptConfig-template.json b/src/scripts/scriptConfig-template.json new file mode 100644 index 00000000..fb911ff3 --- /dev/null +++ b/src/scripts/scriptConfig-template.json @@ -0,0 +1,6 @@ +{ + "publicFlag": true, + "tenantIDs": [""], + "idPattern": "", + "mongoConnectionString": "mongodb://..." +} diff --git a/src/scripts/setCSPublicFlag.ts b/src/scripts/setCSPublicFlag.ts new file mode 100644 index 00000000..2bc6b7e8 --- /dev/null +++ b/src/scripts/setCSPublicFlag.ts @@ -0,0 +1,31 @@ +var MongoClient = require('mongodb'); +var fs = require('fs'); + +// This script sets charging stations public or private +// Filter charging stations by id pattern + +// Use case: simulate charging station for roaming tests +// charging stations are private by default +// set public = true + +// Config +var config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8')); + +// Mongo Connection and Query +if (config && config.mongoConnectionString) { + MongoClient.connect(config.mongoConnectionString, { + useUnifiedTopology: true, + useNewUrlParser: true + }, async function(err, client) { + const db = client.db('evse'); + + for await (const tenantID of config.tenantIDs) { + let response = await db.collection(tenantID + '.chargingstations').updateMany( + { _id: {'$regex': config.idPattern} }, + { $set: { public : config.publicFlag } } + ); + console.log(response.modifiedCount, `Charging Stations with id = %${config.idPattern}% updated. TenantID =`, tenantID); + } + client.close(); + }); +} diff --git a/src/start.ts b/src/start.ts index e841b57e..fb58c2d2 100644 --- a/src/start.ts +++ b/src/start.ts @@ -1,31 +1,49 @@ import Configuration from './utils/Configuration'; import { StationTemplateURL } from './types/ConfigurationData'; +import Utils from './utils/Utils'; import Wrk from './charging-station/Worker'; +import WorkerData from './types/WorkerData'; +import fs from 'fs'; class Bootstrap { - static start() { + static async start() { try { let numStationsTotal = 0; let numConcurrentWorkers = 0; + let worker: Wrk; + let chargingStationsPerWorker = Configuration.getChargingStationsPerWorker(); + let counter = 0; // Start each ChargingStation object in a worker thread if (Configuration.getStationTemplateURLs()) { - Configuration.getStationTemplateURLs().forEach((stationURL: StationTemplateURL) => { + for await (const stationURL of Configuration.getStationTemplateURLs()) { try { const nbStations = stationURL.numberOfStations ? stationURL.numberOfStations : 0; numStationsTotal += nbStations; for (let index = 1; index <= nbStations; index++) { - const worker = new Wrk('./dist/charging-station/StationWorker.js', { + const workerData = { index, - templateFile: stationURL.file, - }, numStationsTotal); - worker.start().catch(() => {}); + templateFile: stationURL.file + } as WorkerData; + if(counter === 0 || counter === chargingStationsPerWorker) { + // Start new worker with one charging station + worker = await new Wrk('./dist/charging-station/StationWorker.js', workerData, numStationsTotal); + worker.start().catch(() => {}); + counter = 0; + // Start workers sequentially to optimize memory at start time + await Utils.sleep(500); + } else { + // Add new charging station to existing Worker + worker.startNewChargingStation(workerData, numStationsTotal) + } + counter++; + // Start charging station sequentially to optimize memory at start time numConcurrentWorkers = worker.concurrentWorkers; } } catch (error) { // eslint-disable-next-line no-console console.log('Charging station start with template file ' + stationURL.file + ' error ' + JSON.stringify(error, null, ' ')); } - }); + } } else { console.log('No stationTemplateURLs defined in configuration, exiting'); } diff --git a/src/types/ConfigurationData.ts b/src/types/ConfigurationData.ts index 371e9c5d..e056471c 100644 --- a/src/types/ConfigurationData.ts +++ b/src/types/ConfigurationData.ts @@ -12,6 +12,8 @@ export default interface ConfigurationData { distributeStationsToTenantsEqually?: boolean; useWorkerPool?: boolean; workerPoolSize?: number; + chargingStationsPerWorker: number; + chargingStationIdSuffix: string; logFormat?: string; logLevel?: string; logRotate?: boolean; diff --git a/src/types/ocpp/1.6/Requests.ts b/src/types/ocpp/1.6/Requests.ts index 1b3e2569..e7e66223 100644 --- a/src/types/ocpp/1.6/Requests.ts +++ b/src/types/ocpp/1.6/Requests.ts @@ -8,6 +8,7 @@ export enum RequestCommand { HEARTBEAT = 'Heartbeat', STATUS_NOTIFICATION = 'StatusNotification', CHANGE_CONFIGURATION = 'ChangeConfiguration', + AUTHORIZE = 'Authorize', START_TRANSACTION = 'StartTransaction', STOP_TRANSACTION = 'StopTransaction', METERVALUES = 'MeterValues' diff --git a/src/types/ocpp/1.6/Transaction.ts b/src/types/ocpp/1.6/Transaction.ts index 7b072e70..22fb6080 100644 --- a/src/types/ocpp/1.6/Transaction.ts +++ b/src/types/ocpp/1.6/Transaction.ts @@ -29,6 +29,14 @@ export interface IdTagInfo { expiryDate?: Date; } +export interface AuthorizeRequest { + idTag: string; + +} +export interface AuthorizeResponse { + idTagInfo: IdTagInfo; +} + export interface StartTransactionRequest { connectorId: number; idTag: string; diff --git a/src/utils/Configuration.ts b/src/utils/Configuration.ts index ca98427e..090e2e2c 100644 --- a/src/utils/Configuration.ts +++ b/src/utils/Configuration.ts @@ -45,6 +45,14 @@ export default class Configuration { return Configuration.getConfig().workerPoolSize; } + static getChargingStationsPerWorker(): number { + return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'chargingStationsPerWorker') ? Configuration.getConfig().chargingStationsPerWorker : 1; + } + + static getChargingStationIdSuffix(): string { + return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'chargingStationIdSuffix') ? Configuration.getConfig().chargingStationIdSuffix : ''; + } + static getLogConsole(): boolean { Configuration.deprecateConfigurationKey('consoleLog', 'Use \'logConsole\' instead'); return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logConsole') ? Configuration.getConfig().logConsole : false; diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index 7afe4cac..6e5eb697 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -34,4 +34,6 @@ export default class Constants { static readonly CHARGING_STATION_ATG_WAIT_TIME = 2000; // Ms static readonly TRANSACTION_DEFAULT_IDTAG = '00000000'; + + static readonly START_NEW_CHARGING_STATION = 'startNewChargingStation'; }