# config
src/assets/config.json
+src/scripts/scriptConfig.json
manifest.yml
# Logs
# MTA
*.mta
mta_archives/
-src/scripts/scriptConfig.json
"dev": true
},
"@types/node": {
- "version": "14.14.21",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz",
- "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==",
+ "version": "14.14.22",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
+ "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==",
"dev": true
},
"@types/offscreencanvas": {
"utf-8-validate": "^5.0.4"
},
"devDependencies": {
- "@types/node": "^14.14.21",
+ "@types/node": "^14.14.22",
"@types/uuid": "^8.3.0",
"@types/worker-threads-pool": "^2.0.0",
"@types/ws": "^7.4.0",
"useWorkerPool": false,
"workerPoolSize": 16,
"chargingStationsPerWorker": 1,
- "chargingStationIdSuffix": "",
"stationTemplateURLs": [
{
"file": "./src/assets/station-templates/siemens.station-template.json",
{
"authorizationFile": "./src/assets/authorization-tags.json",
"baseName": "CS-ABB",
+ "nameSuffix": "Roaming",
"chargePointModel": "MD_TERRA_53",
"chargePointVendor": "ABB",
"firmwareVersion": "4.0.4.22",
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": true
+ "stopOnConnectionFailure": true,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
"maxDelayBetweenTwoTransactions": 30,
"probabilityOfStart": 1,
"stopAfterHours": 0.3,
- "stopOnConnectionFailure": false
+ "stopOnConnectionFailure": false,
+ "requireAuthorize": false
},
"Connectors": {
"0": {},
private async startTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise<StartTransactionResponse> {
if (self._chargingStation.hasAuthorizedTags()) {
const tagId = self._chargingStation.getRandomTagId();
- logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + 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 {
+ if (self._chargingStation.stationInfo.AutomaticTransactionGenerator.requireAuthorize) {
+ // Authorize tagId
+ const authorizeResponse = await self._chargingStation.sendAuthorize(tagId);
+ if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
+ logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
+ // Start transaction
+ return await self._chargingStation.sendStartTransaction(connectorId, tagId);
+ }
return authorizeResponse as StartTransactionResponse;
}
+ logger.info(self._logPrefix(connectorId) + ' start transaction for tagID ' + tagId);
+ // Start transaction
+ return await self._chargingStation.sendStartTransaction(connectorId, tagId);
}
logger.info(self._logPrefix(connectorId) + ' start transaction without a tagID');
return await self._chargingStation.sendStartTransaction(connectorId);
let instanceIndex = process.env.CF_INSTANCE_INDEX ? process.env.CF_INSTANCE_INDEX : 0;
instanceIndex = instanceIndex > 0 ? instanceIndex : '';
- const idSuffix = Configuration.getChargingStationIdSuffix();
+ const idSuffix = stationTemplate.nameSuffix ? stationTemplate.nameSuffix : '';
- return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + instanceIndex + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4) + idSuffix;
+ return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + instanceIndex.toString() + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4) + idSuffix;
}
_buildStationInfo(): ChargingStationInfo {
}
_startAuthorizationFileMonitoring(): void {
- fs.watch(this._getAuthorizationFile()).on("change", e => {
+ fs.watch(this._getAuthorizationFile()).on('change', (e) => {
try {
logger.debug(this._logPrefix() + ' Authorization file ' + this._getAuthorizationFile() + ' have changed, reload');
// Initialize _authorizedTags
}
_startStationTemplateFileMonitoring(): void {
- fs.watch(this._stationTemplateFile).on("change", e => {
+ fs.watch(this._stationTemplateFile).on('change', (e) => {
try {
logger.debug(this._logPrefix() + ' Template file ' + this._stationTemplateFile + ' have changed, reload');
// Initialize
async sendAuthorize(idTag?: string): Promise<AuthorizeResponse> {
try {
const payload: AuthorizeRequest = {
- ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG },
+ ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
};
return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, RequestCommand.AUTHORIZE) as AuthorizeResponse;
} catch (error) {
try {
const payload: StartTransactionRequest = {
connectorId,
- ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG },
+ ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
meterStart: 0,
timestamp: new Date().toISOString(),
};
return;
}
- if (payload.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
+ if (payload?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
this.getConnector(connectorId).transactionStarted = true;
this.getConnector(connectorId).transactionId = payload.transactionId;
this.getConnector(connectorId).idTag = requestPayload.idTag;
this._startMeterValues(connectorId,
configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
} else {
- logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo.status + ', idTag ' + requestPayload.idTag);
+ logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
this._resetTransactionOnConnector(connectorId);
await this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE);
}
import { isMainThread, parentPort, workerData } from 'worker_threads';
-import Constants from '../utils/Constants';
import ChargingStation from './ChargingStation';
+import Constants from '../utils/Constants';
if (!isMainThread) {
const station = new ChargingStation(workerData.index as number, workerData.templateFile as string);
}
function addListener() {
- parentPort.setMaxListeners(1000);
- parentPort.on("message", e => {
- if (e.id === Constants.START_NEW_CHARGING_STATION) {
- startChargingStation(e.workerData);
+ parentPort.setMaxListeners(Constants.MAX_LISTENERS);
+ parentPort.on('message', (e) => {
+ if (e.id === Constants.START_CHARGING_STATION) {
+ startChargingStation(e.workerData);
}
});
}
import { Worker, WorkerOptions } from 'worker_threads';
import Configuration from '../utils/Configuration';
+import Constants from '../utils/Constants';
import Pool from 'worker-threads-pool';
import WorkerData from '../types/WorkerData';
-import Constants from '../utils/Constants';
export default class Wrk {
private _workerScript: string;
*/
async start(): Promise<Worker> {
if (Configuration.useWorkerPool()) {
- this._startWorkerWithPool();
+ await this._startWorkerWithPool();
} else {
- this._startWorker();
+ await this._startWorker();
}
return this._worker;
}
- /**
+ /**
*
- * @return {Promise}
+ * @return {void}
* @public
*/
- async startNewChargingStation(workerData: WorkerData, numConcurrentWorkers: number): Promise<void> {
+ addChargingStation(workerData: WorkerData, numConcurrentWorkers: number): void {
this._workerData = workerData;
this._index = workerData.index;
this._concurrentWorkers = numConcurrentWorkers;
- this._worker.postMessage({ id : Constants.START_NEW_CHARGING_STATION, workerData: workerData });
+ this._worker.postMessage({ id : Constants.START_CHARGING_STATION, workerData: workerData });
}
/**
-var MongoClient = require('mongodb');
-var fs = require('fs');
+import MongoClient from 'mongodb';
+import fs from 'fs';
// This script deletes charging stations
// Filter charging stations by id pattern
// Delete these charging stations all at once
// Config
-var config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'));
+const 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) {
+ }, 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} }
+ const response = await db.collection(tenantID + '.chargingstations').deleteMany(
+ { _id: { '$regex': config.idPattern } }
);
console.log(response.deletedCount, `Charging Stations with id = %${config.idPattern}% deleted. TenantID =`, tenantID);
}
{
"publicFlag": true,
- "tenantIDs": [""],
+ "tenantIDs": [
+ ""
+ ],
"idPattern": "",
"mongoConnectionString": "mongodb://..."
}
-var MongoClient = require('mongodb');
-var fs = require('fs');
+import MongoClient from 'mongodb';
+import fs from 'fs';
// This script sets charging stations public or private
// Filter charging stations by id pattern
// set public = true
// Config
-var config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'));
+const 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) {
+ }, 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 } }
+ const 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);
}
import Configuration from './utils/Configuration';
-import { StationTemplateURL } from './types/ConfigurationData';
+import Constants from './utils/Constants';
import Utils from './utils/Utils';
-import Wrk from './charging-station/Worker';
import WorkerData from './types/WorkerData';
-import fs from 'fs';
+import Wrk from './charging-station/Worker';
class Bootstrap {
static async start() {
let numStationsTotal = 0;
let numConcurrentWorkers = 0;
let worker: Wrk;
- let chargingStationsPerWorker = Configuration.getChargingStationsPerWorker();
+ const chargingStationsPerWorker = Configuration.getChargingStationsPerWorker();
let counter = 0;
// Start each ChargingStation object in a worker thread
if (Configuration.getStationTemplateURLs()) {
index,
templateFile: stationURL.file
} as WorkerData;
- if(counter === 0 || counter === chargingStationsPerWorker) {
+ 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(() => {});
+ worker = 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);
+ await Utils.sleep(Constants.START_WORKER_DELAY);
} else {
- // Add new charging station to existing Worker
- worker.startNewChargingStation(workerData, numStationsTotal)
+ // Add charging station to existing Worker
+ worker.addChargingStation(workerData, numStationsTotal);
}
counter++;
- // Start charging station sequentially to optimize memory at start time
numConcurrentWorkers = worker.concurrentWorkers;
}
} catch (error) {
maxDelayBetweenTwoTransactions: number;
probabilityOfStart: number;
stopAfterHours: number;
- stopOnConnectionFailure: boolean
+ stopOnConnectionFailure: boolean;
+ requireAuthorize: boolean
}
export default interface ChargingStationTemplate {
supervisionURL?: string;
authorizationFile?: string;
baseName: string;
+ nameSuffix?: string;
fixedName?: string;
chargePointModel: string;
chargePointVendor: string;
distributeStationsToTenantsEqually?: boolean;
useWorkerPool?: boolean;
workerPoolSize?: number;
- chargingStationsPerWorker: number;
- chargingStationIdSuffix: string;
+ chargingStationsPerWorker?: number;
logFormat?: string;
logLevel?: string;
logRotate?: boolean;
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;
static readonly CHARGING_STATION_DEFAULT_RESET_TIME = 60000; // Ms
static readonly CHARGING_STATION_ATG_WAIT_TIME = 2000; // Ms
- static readonly TRANSACTION_DEFAULT_IDTAG = '00000000';
+ static readonly TRANSACTION_DEFAULT_TAGID = '00000000';
- static readonly START_NEW_CHARGING_STATION = 'startNewChargingStation';
+ static readonly MAX_LISTENERS = 1000;
+
+ static readonly START_WORKER_DELAY = 500;
+ static readonly START_CHARGING_STATION = 'startChargingStation';
}