import PerformanceStatistics from '../performance/PerformanceStatistics';
import { Status } from '../types/AutomaticTransactionGenerator';
import Utils from '../utils/Utils';
-import getLogger from '../utils/Logger';
+import logger from '../utils/Logger';
export default class AutomaticTransactionGenerator {
public started: boolean;
public start(): void {
if (this.started) {
- getLogger().error(`${this.logPrefix()} trying to start while already started`);
+ logger.error(`${this.logPrefix()} trying to start while already started`);
return;
}
this.startConnectors();
public stop(): void {
if (!this.started) {
- getLogger().error(`${this.logPrefix()} trying to stop while not started`);
+ logger.error(`${this.logPrefix()} trying to stop while not started`);
return;
}
this.stopConnectors();
private async internalStartConnector(connectorId: number): Promise<void> {
this.initStartConnectorStatus(connectorId);
- getLogger().info(this.logPrefix(connectorId) + ' started on connector and will run for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stopDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
+ logger.info(this.logPrefix(connectorId) + ' started on connector and will run for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stopDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
while (this.connectorsStatus.get(connectorId).start) {
if ((new Date()) > this.connectorsStatus.get(connectorId).stopDate) {
this.stopConnector(connectorId);
break;
}
if (!this.chargingStation.isInAcceptedState()) {
- getLogger().error(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is not in accepted state');
+ logger.error(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is not in accepted state');
this.stopConnector(connectorId);
break;
}
if (!this.chargingStation.isChargingStationAvailable()) {
- getLogger().info(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is unavailable');
+ logger.info(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is unavailable');
this.stopConnector(connectorId);
break;
}
if (!this.chargingStation.isConnectorAvailable(connectorId)) {
- getLogger().info(`${this.logPrefix(connectorId)} entered in transaction loop while the connector ${connectorId} is unavailable`);
+ logger.info(`${this.logPrefix(connectorId)} entered in transaction loop while the connector ${connectorId} is unavailable`);
this.stopConnector(connectorId);
break;
}
if (!this.chargingStation?.ocppRequestService) {
- getLogger().info(`${this.logPrefix(connectorId)} transaction loop waiting for charging station service to be initialized`);
+ logger.info(`${this.logPrefix(connectorId)} transaction loop waiting for charging station service to be initialized`);
do {
await Utils.sleep(Constants.CHARGING_STATION_ATG_INITIALIZATION_TIME);
} while (!this.chargingStation?.ocppRequestService);
}
const wait = Utils.getRandomInteger(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
- getLogger().info(this.logPrefix(connectorId) + ' waiting for ' + Utils.formatDurationMilliSeconds(wait));
+ logger.info(this.logPrefix(connectorId) + ' waiting for ' + Utils.formatDurationMilliSeconds(wait));
await Utils.sleep(wait);
const start = Utils.secureRandom();
if (start < this.chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
const startResponse = await this.startTransaction(connectorId);
this.connectorsStatus.get(connectorId).startTransactionRequests++;
if (startResponse?.idTagInfo?.status !== AuthorizationStatus.ACCEPTED) {
- getLogger().warn(this.logPrefix(connectorId) + ' start transaction rejected');
+ logger.warn(this.logPrefix(connectorId) + ' start transaction rejected');
this.connectorsStatus.get(connectorId).rejectedStartTransactionRequests++;
} else {
// Wait until end of transaction
const waitTrxEnd = Utils.getRandomInteger(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
- getLogger().info(this.logPrefix(connectorId) + ' transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString() + ' started and will stop in ' + Utils.formatDurationMilliSeconds(waitTrxEnd));
+ logger.info(this.logPrefix(connectorId) + ' transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString() + ' started and will stop in ' + Utils.formatDurationMilliSeconds(waitTrxEnd));
this.connectorsStatus.get(connectorId).acceptedStartTransactionRequests++;
await Utils.sleep(waitTrxEnd);
// Stop transaction
- getLogger().info(this.logPrefix(connectorId) + ' stop transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString());
+ logger.info(this.logPrefix(connectorId) + ' stop transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString());
await this.stopTransaction(connectorId);
}
} else {
this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions++;
this.connectorsStatus.get(connectorId).skippedTransactions++;
- getLogger().info(this.logPrefix(connectorId) + ' skipped consecutively ' + this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions.toString() + '/' + this.connectorsStatus.get(connectorId).skippedTransactions.toString() + ' transaction(s)');
+ logger.info(this.logPrefix(connectorId) + ' skipped consecutively ' + this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions.toString() + '/' + this.connectorsStatus.get(connectorId).skippedTransactions.toString() + ' transaction(s)');
}
this.connectorsStatus.get(connectorId).lastRunDate = new Date();
}
await this.stopTransaction(connectorId);
this.connectorsStatus.get(connectorId).stoppedDate = new Date();
- getLogger().info(this.logPrefix(connectorId) + ' stopped on connector and lasted for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stoppedDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
- getLogger().debug(`${this.logPrefix(connectorId)} connector status %j`, this.connectorsStatus.get(connectorId));
+ logger.info(this.logPrefix(connectorId) + ' stopped on connector and lasted for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stoppedDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
+ logger.debug(`${this.logPrefix(connectorId)} connector status %j`, this.connectorsStatus.get(connectorId));
}
private startConnector(connectorId: number): void {
this.connectorsStatus.get(connectorId).authorizeRequests++;
if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
this.connectorsStatus.get(connectorId).acceptedAuthorizeRequests++;
- getLogger().info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
+ logger.info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
// Start transaction
startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(connectorId, idTag);
PerformanceStatistics.endMeasure(measureId, beginId);
PerformanceStatistics.endMeasure(measureId, beginId);
return authorizeResponse;
}
- getLogger().info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
+ logger.info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
// Start transaction
startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(connectorId, idTag);
PerformanceStatistics.endMeasure(measureId, beginId);
return startResponse;
}
- getLogger().info(this.logPrefix(connectorId) + ' start transaction without an idTag');
+ logger.info(this.logPrefix(connectorId) + ' start transaction without an idTag');
startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(connectorId);
PerformanceStatistics.endMeasure(measureId, beginId);
return startResponse;
reason);
this.connectorsStatus.get(connectorId).stopTransactionRequests++;
} else {
- getLogger().warn(`${this.logPrefix(connectorId)} trying to stop a not started transaction${transactionId ? ' ' + transactionId.toString() : ''}`);
+ logger.warn(`${this.logPrefix(connectorId)} trying to stop a not started transaction${transactionId ? ' ' + transactionId.toString() : ''}`);
}
PerformanceStatistics.endMeasure(measureId, beginId);
return stopResponse;
import Utils from '../utils/Utils';
import crypto from 'crypto';
import fs from 'fs';
-import getLogger from '../utils/Logger';
+import logger from '../utils/Logger';
import { parentPort } from 'worker_threads';
import path from 'path';
export default class ChargingStation {
+ public readonly id: string;
public readonly stationTemplateFile: string;
public authorizedTags: string[];
public stationInfo!: ChargingStationInfo;
public performanceStatistics!: PerformanceStatistics;
public heartbeatSetInterval!: NodeJS.Timeout;
public ocppRequestService!: OCPPRequestService;
- private readonly id: string;
private readonly index: number;
private bootNotificationRequest!: BootNotificationRequest;
private bootNotificationResponse!: BootNotificationResponse | null;
this.id = Utils.generateUUID();
this.index = index;
this.stationTemplateFile = stationTemplateFile;
- this.connectors = new Map<number, ConnectorStatus>();
- this.initialize();
-
this.stopped = false;
this.wsConnectionRestarted = false;
this.autoReconnectRetryCount = 0;
-
+ this.connectors = new Map<number, ConnectorStatus>();
this.requests = new Map<string, CachedRequest>();
this.messageBuffer = new Set<string>();
-
+ this.initialize();
this.authorizedTags = this.getAuthorizedTags();
}
}
public isConnectorAvailable(id: number): boolean {
- return this.getConnectorStatus(id).availability === AvailabilityType.OPERATIVE;
+ return id > 0 && this.getConnectorStatus(id).availability === AvailabilityType.OPERATIVE;
}
public getNumberOfConnectors(): number {
defaultVoltageOut = Voltage.VOLTAGE_400;
break;
default:
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new Error(errMsg);
}
return !Utils.isUndefined(this.stationInfo.voltageOut) ? this.stationInfo.voltageOut : defaultVoltageOut;
public getSampledValueTemplate(connectorId: number, measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
phase?: MeterValuePhase): SampledValueTemplate | undefined {
if (!Constants.SUPPORTED_MEASURANDS.includes(measurand)) {
- getLogger().warn(`${this.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
+ logger.warn(`${this.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
return;
}
if (measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && !this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(measurand)) {
- getLogger().debug(`${this.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId} not found in '${StandardParametersKey.MeterValuesSampledData}' OCPP parameter`);
+ logger.debug(`${this.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId} not found in '${StandardParametersKey.MeterValuesSampledData}' OCPP parameter`);
return;
}
const sampledValueTemplates: SampledValueTemplate[] = this.getConnectorStatus(connectorId).MeterValues;
for (let index = 0; !Utils.isEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length; index++) {
if (!Constants.SUPPORTED_MEASURANDS.includes(sampledValueTemplates[index]?.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER)) {
- getLogger().warn(`${this.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
+ logger.warn(`${this.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
} else if (phase && sampledValueTemplates[index]?.phase === phase && sampledValueTemplates[index]?.measurand === measurand
&& this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(measurand)) {
return sampledValueTemplates[index];
}
if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
const errorMsg = `${this.logPrefix()} Missing MeterValues for default measurand '${measurand}' in template on connectorId ${connectorId}`;
- getLogger().error(errorMsg);
+ logger.error(errorMsg);
throw new Error(errorMsg);
}
- getLogger().debug(`${this.logPrefix()} No MeterValues for measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
+ logger.debug(`${this.logPrefix()} No MeterValues for measurand '${measurand}' ${phase ? `on phase ${phase} ` : ''}in template on connectorId ${connectorId}`);
}
public getAutomaticTransactionGeneratorRequireAuthorize(): boolean {
this.heartbeatSetInterval = setInterval(async (): Promise<void> => {
await this.ocppRequestService.sendHeartbeat();
}, this.getHeartbeatInterval());
- getLogger().info(this.logPrefix() + ' Heartbeat started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
+ logger.info(this.logPrefix() + ' Heartbeat started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
} else if (this.heartbeatSetInterval) {
- getLogger().info(this.logPrefix() + ' Heartbeat already started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
+ logger.info(this.logPrefix() + ' Heartbeat already started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
} else {
- getLogger().error(`${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval() ? Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()) : this.getHeartbeatInterval()}, not starting the heartbeat`);
+ logger.error(`${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval() ? Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()) : this.getHeartbeatInterval()}, not starting the heartbeat`);
}
}
public startMeterValues(connectorId: number, interval: number): void {
if (connectorId === 0) {
- getLogger().error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId.toString()}`);
+ logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId.toString()}`);
return;
}
if (!this.getConnectorStatus(connectorId)) {
- getLogger().error(`${this.logPrefix()} Trying to start MeterValues on non existing connector Id ${connectorId.toString()}`);
+ logger.error(`${this.logPrefix()} Trying to start MeterValues on non existing connector Id ${connectorId.toString()}`);
return;
}
if (!this.getConnectorStatus(connectorId)?.transactionStarted) {
- getLogger().error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction started`);
+ logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction started`);
return;
} else if (this.getConnectorStatus(connectorId)?.transactionStarted && !this.getConnectorStatus(connectorId)?.transactionId) {
- getLogger().error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction id`);
+ logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction id`);
return;
}
if (interval > 0) {
await this.ocppRequestService.sendMeterValues(connectorId, this.getConnectorStatus(connectorId).transactionId, interval);
}, interval);
} else {
- getLogger().error(`${this.logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${interval ? Utils.formatDurationMilliSeconds(interval) : interval}, not sending MeterValues`);
+ logger.error(`${this.logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${interval ? Utils.formatDurationMilliSeconds(interval) : interval}, not sending MeterValues`);
}
}
reboot,
});
} else {
- getLogger().error(`${this.logPrefix()} Trying to add an already existing configuration key: %j`, keyFound);
+ logger.error(`${this.logPrefix()} Trying to add an already existing configuration key: %j`, keyFound);
}
}
const keyIndex = this.configuration.configurationKey.indexOf(keyFound);
this.configuration.configurationKey[keyIndex].value = value;
} else {
- getLogger().error(`${this.logPrefix()} Trying to set a value on a non existing configuration key: %j`, { key, value });
+ logger.error(`${this.logPrefix()} Trying to set a value on a non existing configuration key: %j`, { key, value });
}
}
private handleUnsupportedVersion(version: OCPPVersion) {
const errMsg = `${this.logPrefix()} Unsupported protocol version '${version}' configured in template file ${this.stationTemplateFile}`;
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new Error(errMsg);
}
// Build connectors if needed
const maxConnectors = this.getMaxNumberOfConnectors();
if (maxConnectors <= 0) {
- getLogger().warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with ${maxConnectors} connectors`);
+ logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with ${maxConnectors} connectors`);
}
const templateMaxConnectors = this.getTemplateMaxNumberOfConnectors();
if (templateMaxConnectors <= 0) {
- getLogger().warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector configuration`);
+ logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector configuration`);
}
if (!this.stationInfo.Connectors[0]) {
- getLogger().warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector Id 0 configuration`);
+ logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector Id 0 configuration`);
}
// Sanity check
if (maxConnectors > (this.stationInfo.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) && !this.stationInfo.randomConnectors) {
- getLogger().warn(`${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${this.stationTemplateFile}, forcing random connector configurations affectation`);
+ logger.warn(`${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${this.stationTemplateFile}, forcing random connector configurations affectation`);
this.stationInfo.randomConnectors = true;
}
const connectorsConfigHash = crypto.createHash('sha256').update(JSON.stringify(this.stationInfo.Connectors) + maxConnectors.toString()).digest('hex');
this.wsConfiguredConnectionUrl = new URL(this.getConfiguredSupervisionUrl().href + '/' + this.stationInfo.chargingStationId);
switch (this.getOcppVersion()) {
case OCPPVersion.VERSION_16:
- this.ocppIncomingRequestService = new OCPP16IncomingRequestService(this);
- this.ocppRequestService = new OCPP16RequestService(this, new OCPP16ResponseService(this));
+ this.ocppIncomingRequestService = OCPP16IncomingRequestService.getInstance<OCPP16IncomingRequestService>(this);
+ this.ocppRequestService = OCPP16RequestService.getInstance<OCPP16RequestService>(this, OCPP16ResponseService.getInstance<OCPP16ResponseService>(this));
break;
default:
this.handleUnsupportedVersion(this.getOcppVersion());
}
this.stationInfo.powerDivider = this.getPowerDivider();
if (this.getEnableStatistics()) {
- this.performanceStatistics = new PerformanceStatistics(this.stationInfo.chargingStationId, this.wsConnectionUrl);
+ this.performanceStatistics = PerformanceStatistics.getInstance(this.id, this.stationInfo.chargingStationId, this.wsConnectionUrl);
}
}
}
private async onOpen(): Promise<void> {
- getLogger().info(`${this.logPrefix()} Connected to OCPP server through ${this.wsConnectionUrl.toString()}`);
+ logger.info(`${this.logPrefix()} Connected to OCPP server through ${this.wsConnectionUrl.toString()}`);
if (!this.isInAcceptedState()) {
// Send BootNotification
let registrationRetryCount = 0;
this.flushMessageBuffer();
}
} else {
- getLogger().error(`${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`);
+ logger.error(`${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`);
}
this.autoReconnectRetryCount = 0;
this.wsConnectionRestarted = false;
// Normal close
case WebSocketCloseEventStatusCode.CLOSE_NORMAL:
case WebSocketCloseEventStatusCode.CLOSE_NO_STATUS:
- getLogger().info(`${this.logPrefix()} WebSocket normally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
+ logger.info(`${this.logPrefix()} WebSocket normally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
this.autoReconnectRetryCount = 0;
break;
// Abnormal close
default:
- getLogger().error(`${this.logPrefix()} WebSocket abnormally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
+ logger.error(`${this.logPrefix()} WebSocket abnormally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
await this.reconnect(code);
break;
}
// Error
default:
errMsg = `${this.logPrefix()} Wrong message type ${messageType}`;
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg);
}
} catch (error) {
// Log
- getLogger().error('%s Incoming OCPP message %j matching cached request %j processing error %j', this.logPrefix(), data.toString(), this.requests.get(messageId), error);
+ logger.error('%s Incoming OCPP message %j matching cached request %j processing error %j', this.logPrefix(), data.toString(), this.requests.get(messageId), error);
// Send error
messageType === MessageType.CALL_MESSAGE && await this.ocppRequestService.sendError(messageId, error as OCPPError, commandName);
}
}
private onPing(): void {
- getLogger().debug(this.logPrefix() + ' Received a WS ping (rfc6455) from the server');
+ logger.debug(this.logPrefix() + ' Received a WS ping (rfc6455) from the server');
}
private onPong(): void {
- getLogger().debug(this.logPrefix() + ' Received a WS pong (rfc6455) from the server');
+ logger.debug(this.logPrefix() + ' Received a WS pong (rfc6455) from the server');
}
private async onError(error: WSError): Promise<void> {
- getLogger().error(this.logPrefix() + ' WebSocket error: %j', error);
+ logger.error(this.logPrefix() + ' WebSocket error: %j', error);
// switch (error.code) {
// case 'ECONNREFUSED':
// await this.reconnect(error);
FileUtils.handleFileException(this.logPrefix(), 'Authorization', authorizationFile, error as NodeJS.ErrnoException);
}
} else {
- getLogger().info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile);
+ logger.info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile);
}
return authorizedTags;
}
this.stopHeartbeat();
// Stop the ATG
if (this.stationInfo.AutomaticTransactionGenerator.enable &&
- this.automaticTransactionGenerator &&
- this.automaticTransactionGenerator.started) {
+ this.automaticTransactionGenerator?.started) {
this.automaticTransactionGenerator.stop();
} else {
for (const connectorId of this.connectors.keys()) {
this.wsConnection.ping((): void => { /* This is intentional */ });
}
}, webSocketPingInterval * 1000);
- getLogger().info(this.logPrefix() + ' WebSocket ping started every ' + Utils.formatDurationSeconds(webSocketPingInterval));
+ logger.info(this.logPrefix() + ' WebSocket ping started every ' + Utils.formatDurationSeconds(webSocketPingInterval));
} else if (this.webSocketPingSetInterval) {
- getLogger().info(this.logPrefix() + ' WebSocket ping every ' + Utils.formatDurationSeconds(webSocketPingInterval) + ' already started');
+ logger.info(this.logPrefix() + ' WebSocket ping every ' + Utils.formatDurationSeconds(webSocketPingInterval) + ' already started');
} else {
- getLogger().error(`${this.logPrefix()} WebSocket ping interval set to ${webSocketPingInterval ? Utils.formatDurationSeconds(webSocketPingInterval) : webSocketPingInterval}, not starting the WebSocket ping`);
+ logger.error(`${this.logPrefix()} WebSocket ping interval set to ${webSocketPingInterval ? Utils.formatDurationSeconds(webSocketPingInterval) : webSocketPingInterval}, not starting the WebSocket ping`);
}
}
private warnDeprecatedTemplateKey(template: ChargingStationTemplate, key: string, chargingStationId: string, logMsgToAppend = ''): void {
if (!Utils.isUndefined(template[key])) {
- getLogger().warn(`${Utils.logPrefix(` ${chargingStationId} |`)} Deprecated template key '${key}' usage in file '${this.stationTemplateFile}'${logMsgToAppend && '. ' + logMsgToAppend}`);
+ logger.warn(`${Utils.logPrefix(` ${chargingStationId} |`)} Deprecated template key '${key}' usage in file '${this.stationTemplateFile}'${logMsgToAppend && '. ' + logMsgToAppend}`);
}
}
if (this.index <= supervisionUrls.length) {
urlIndex = this.index - 1;
} else {
- getLogger().warn(`${this.logPrefix()} No more configured supervision urls available, using the first one`);
+ logger.warn(`${this.logPrefix()} No more configured supervision urls available, using the first one`);
}
break;
default:
- getLogger().error(`${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${SupervisionUrlDistribution.ROUND_ROBIN}`);
+ logger.error(`${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${SupervisionUrlDistribution.ROUND_ROBIN}`);
urlIndex = (this.index - 1) % supervisionUrls.length;
break;
}
if (HeartBeatInterval) {
return Utils.convertToInt(HeartBeatInterval.value) * 1000;
}
- !this.stationInfo.autoRegister && getLogger().warn(`${this.logPrefix()} Heartbeat interval configuration key not set, using default value: ${Constants.DEFAULT_HEARTBEAT_INTERVAL}`);
+ !this.stationInfo.autoRegister && logger.warn(`${this.logPrefix()} Heartbeat interval configuration key not set, using default value: ${Constants.DEFAULT_HEARTBEAT_INTERVAL}`);
return Constants.DEFAULT_HEARTBEAT_INTERVAL;
}
break;
}
this.wsConnection = new WebSocket(this.wsConnectionUrl, protocol, options);
- getLogger().info(this.logPrefix() + ' Open OCPP connection to URL ' + this.wsConnectionUrl.toString());
+ logger.info(this.logPrefix() + ' Open OCPP connection to URL ' + this.wsConnectionUrl.toString());
}
private stopMeterValues(connectorId: number) {
fs.watch(authorizationFile, (event, filename) => {
if (filename && event === 'change') {
try {
- getLogger().debug(this.logPrefix() + ' Authorization file ' + authorizationFile + ' have changed, reload');
+ logger.debug(this.logPrefix() + ' Authorization file ' + authorizationFile + ' have changed, reload');
// Initialize authorizedTags
this.authorizedTags = this.getAuthorizedTags();
} catch (error) {
- getLogger().error(this.logPrefix() + ' Authorization file monitoring error: %j', error);
+ logger.error(this.logPrefix() + ' Authorization file monitoring error: %j', error);
}
}
});
FileUtils.handleFileException(this.logPrefix(), 'Authorization', authorizationFile, error as NodeJS.ErrnoException);
}
} else {
- getLogger().info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile + '. Not monitoring changes');
+ logger.info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile + '. Not monitoring changes');
}
}
fs.watch(this.stationTemplateFile, (event, filename): void => {
if (filename && event === 'change') {
try {
- getLogger().debug(this.logPrefix() + ' Template file ' + this.stationTemplateFile + ' have changed, reload');
+ logger.debug(this.logPrefix() + ' Template file ' + this.stationTemplateFile + ' have changed, reload');
// Initialize
this.initialize();
// Restart the ATG
}
// FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
} catch (error) {
- getLogger().error(this.logPrefix() + ' Charging station template file monitoring error: %j', error);
+ logger.error(this.logPrefix() + ' Charging station template file monitoring error: %j', error);
}
}
});
// Stop the ATG if needed
if (this.stationInfo.AutomaticTransactionGenerator.enable &&
this.stationInfo.AutomaticTransactionGenerator.stopOnConnectionFailure &&
- this.automaticTransactionGenerator &&
- this.automaticTransactionGenerator.started) {
+ this.automaticTransactionGenerator?.started) {
this.automaticTransactionGenerator.stop();
}
if (this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() || this.getAutoReconnectMaxRetries() === -1) {
this.autoReconnectRetryCount++;
const reconnectDelay = (this.getReconnectExponentialDelay() ? Utils.exponentialDelay(this.autoReconnectRetryCount) : this.getConnectionTimeout() * 1000);
const reconnectTimeout = (reconnectDelay - 100) > 0 && reconnectDelay;
- getLogger().error(`${this.logPrefix()} WebSocket: connection retry in ${Utils.roundTo(reconnectDelay, 2)}ms, timeout ${reconnectTimeout}ms`);
+ logger.error(`${this.logPrefix()} WebSocket: connection retry in ${Utils.roundTo(reconnectDelay, 2)}ms, timeout ${reconnectTimeout}ms`);
await Utils.sleep(reconnectDelay);
- getLogger().error(this.logPrefix() + ' WebSocket: reconnecting try #' + this.autoReconnectRetryCount.toString());
+ logger.error(this.logPrefix() + ' WebSocket: reconnecting try #' + this.autoReconnectRetryCount.toString());
this.openWSConnection({ ...this.stationInfo.wsOptions, handshakeTimeout: reconnectTimeout }, true);
this.wsConnectionRestarted = true;
} else if (this.getAutoReconnectMaxRetries() !== -1) {
- getLogger().error(`${this.logPrefix()} WebSocket reconnect failure: max retries reached (${this.autoReconnectRetryCount}) or retry disabled (${this.getAutoReconnectMaxRetries()})`);
+ logger.error(`${this.logPrefix()} WebSocket reconnect failure: max retries reached (${this.autoReconnectRetryCount}) or retry disabled (${this.getAutoReconnectMaxRetries()})`);
}
}
import { IncomingMessage } from 'http';
import UIServiceFactory from './ui-websocket-services/UIServiceFactory';
import Utils from '../utils/Utils';
-import getLogger from '../utils/Logger';
+import logger from '../utils/Logger';
export default class UIWebSocketServer extends Server {
public readonly chargingStations: Set<string>;
throw new BaseError('UI protocol request is not iterable');
}
this.uiServices.get(version).handleMessage(command, payload).catch(() => {
- getLogger().error(`${this.logPrefix()} Error while handling command %s message: %j`, command, payload);
+ logger.error(`${this.logPrefix()} Error while handling command %s message: %j`, command, payload);
});
});
socket.on('error', (error) => {
- getLogger().error(`${this.logPrefix()} Error on WebSocket: %j`, error);
+ logger.error(`${this.logPrefix()} Error on WebSocket: %j`, error);
});
});
}
import { URL } from 'url';
import Utils from '../../../utils/Utils';
import fs from 'fs';
-import getLogger from '../../../utils/Logger';
+import logger from '../../../utils/Logger';
import path from 'path';
import tar from 'tar';
export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
- constructor(chargingStation: ChargingStation) {
+ public constructor(chargingStation: ChargingStation) {
+ if (new.target?.name === 'OCPP16IncomingRequestService') {
+ throw new TypeError('Cannot construct OCPP16IncomingRequestService instances directly');
+ }
super(chargingStation);
this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
[OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
result = await this.incomingRequestHandlers.get(commandName)(commandPayload);
} catch (error) {
// Log
- getLogger().error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
+ logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
throw error;
}
} else {
await Utils.sleep(this.chargingStation.stationInfo.resetTime);
this.chargingStation.start();
});
- getLogger().info(`${this.chargingStation.logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(this.chargingStation.stationInfo.resetTime)}`);
+ logger.info(`${this.chargingStation.logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(this.chargingStation.stationInfo.resetTime)}`);
return Constants.OCPP_RESPONSE_ACCEPTED;
}
private async handleRequestUnlockConnector(commandPayload: UnlockConnectorRequest): Promise<UnlockConnectorResponse> {
const connectorId = commandPayload.connectorId;
if (connectorId === 0) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
}
if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
private handleRequestChangeConfiguration(commandPayload: ChangeConfigurationRequest): ChangeConfigurationResponse {
// JSON request fields type sanity check
if (!Utils.isString(commandPayload.key)) {
- getLogger().error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload);
+ logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload);
}
if (!Utils.isString(commandPayload.value)) {
- getLogger().error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload);
+ logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload);
}
const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true);
if (!keyToChange) {
private handleRequestSetChargingProfile(commandPayload: SetChargingProfileRequest): SetChargingProfileResponse {
if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
- getLogger().error(`${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
+ logger.error(`${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
}
if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE && commandPayload.connectorId !== 0) {
return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
}
this.chargingStation.setChargingProfile(commandPayload.connectorId, commandPayload.csChargingProfiles);
- getLogger().debug(`${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
+ logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
}
private handleRequestClearChargingProfile(commandPayload: ClearChargingProfileRequest): ClearChargingProfileResponse {
if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
- getLogger().error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
+ logger.error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
}
if (commandPayload.connectorId && !Utils.isEmptyArray(this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles)) {
this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles = [];
- getLogger().debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
+ logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
}
if (!commandPayload.connectorId) {
}
if (clearCurrentCP) {
this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles[index] = {} as OCPP16ChargingProfile;
- getLogger().debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
+ logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
clearedCP = true;
}
});
private async handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): Promise<ChangeAvailabilityResponse> {
const connectorId: number = commandPayload.connectorId;
if (!this.chargingStation.getConnectorStatus(connectorId)) {
- getLogger().error(`${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`);
+ logger.error(`${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`);
return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
}
const chargePointStatus: OCPP16ChargePointStatus = commandPayload.type === OCPP16AvailabilityType.OPERATIVE
authorized = true;
}
} else {
- getLogger().warn(`${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`);
+ logger.warn(`${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`);
}
if (authorized) {
// Authorization successful, start transaction
if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
- getLogger().debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
+ logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
return Constants.OCPP_RESPONSE_ACCEPTED;
}
return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
- getLogger().debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
+ logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
return Constants.OCPP_RESPONSE_ACCEPTED;
}
return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
}
- getLogger().warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', idTag ' + idTag + ', availability ' + this.chargingStation.getConnectorStatus(connectorId).availability + ', status ' + this.chargingStation.getConnectorStatus(connectorId).status);
+ logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', idTag ' + idTag + ', availability ' + this.chargingStation.getConnectorStatus(connectorId).availability + ', status ' + this.chargingStation.getConnectorStatus(connectorId).status);
return Constants.OCPP_RESPONSE_REJECTED;
}
private setRemoteStartTransactionChargingProfile(connectorId: number, cp: OCPP16ChargingProfile): boolean {
if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
this.chargingStation.setChargingProfile(connectorId, cp);
- getLogger().debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnectorStatus(connectorId).chargingProfiles);
+ logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnectorStatus(connectorId).chargingProfiles);
return true;
} else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
- getLogger().warn(`${this.chargingStation.logPrefix()} Not allowed to set ${cp.chargingProfilePurpose} charging profile(s) at remote start transaction`);
+ logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${cp.chargingProfilePurpose} charging profile(s) at remote start transaction`);
return false;
} else if (!cp) {
return true;
return Constants.OCPP_RESPONSE_ACCEPTED;
}
}
- getLogger().info(this.chargingStation.logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
+ logger.info(this.chargingStation.logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
return Constants.OCPP_RESPONSE_REJECTED;
}
private async handleRequestGetDiagnostics(commandPayload: GetDiagnosticsRequest): Promise<GetDiagnosticsResponse> {
- getLogger().debug(this.chargingStation.logPrefix() + ' ' + OCPP16IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload);
+ logger.debug(this.chargingStation.logPrefix() + ' ' + OCPP16IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload);
const uri = new URL(commandPayload.location);
if (uri.protocol.startsWith('ftp:')) {
let ftpClient: Client;
if (accessResponse.code === 220) {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
ftpClient.trackProgress(async (info) => {
- getLogger().info(`${this.chargingStation.logPrefix()} ${info.bytes / 1024} bytes transferred from diagnostics archive ${info.name}`);
+ logger.info(`${this.chargingStation.logPrefix()} ${info.bytes / 1024} bytes transferred from diagnostics archive ${info.name}`);
await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.Uploading);
});
uploadResponse = await ftpClient.uploadFrom(path.join(path.resolve(__dirname, '../../../../'), diagnosticsArchive), uri.pathname + diagnosticsArchive);
return this.handleIncomingRequestError(OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error as Error, Constants.OCPP_RESPONSE_EMPTY);
}
} else {
- getLogger().error(`${this.chargingStation.logPrefix()} Unsupported protocol ${uri.protocol} to transfer the diagnostic logs archive`);
+ logger.error(`${this.chargingStation.logPrefix()} Unsupported protocol ${uri.protocol} to transfer the diagnostic logs archive`);
await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed);
return Constants.OCPP_RESPONSE_EMPTY;
}
import { DiagnosticsStatusNotificationRequest, HeartbeatRequest, OCPP16BootNotificationRequest, OCPP16IncomingRequestCommand, OCPP16RequestCommand, StatusNotificationRequest } from '../../../types/ocpp/1.6/Requests';
import { MeterValueUnit, MeterValuesRequest, OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase } from '../../../types/ocpp/1.6/MeterValues';
+import ChargingStation from '../../ChargingStation';
import Constants from '../../../utils/Constants';
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { JsonType } from '../../../types/JsonType';
import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
import OCPPError from '../../../exception/OCPPError';
import OCPPRequestService from '../OCPPRequestService';
+import OCPPResponseService from '../OCPPResponseService';
import { SendParams } from '../../../types/ocpp/Requests';
import Utils from '../../../utils/Utils';
-import getLogger from '../../../utils/Logger';
+import logger from '../../../utils/Logger';
export default class OCPP16RequestService extends OCPPRequestService {
+ public constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) {
+ if (new.target?.name === 'OCPP16RequestService') {
+ throw new TypeError('Cannot construct OCPP16RequestService instances directly');
+ }
+ super(chargingStation, ocppResponseService);
+ }
+
public async sendHeartbeat(params?: SendParams): Promise<void> {
try {
const payload: HeartbeatRequest = {};
meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue));
const sampledValuesIndex = meterValue.sampledValue.length - 1;
if (Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > 100 || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/100`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/100`);
}
}
// Voltage measurand
: Utils.getRandomFloatRounded(maxPower / unitDivider);
break;
default:
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
}
meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases));
const sampledValuesIndex = meterValue.sampledValue.length - 1;
const maxPowerRounded = Utils.roundTo(maxPower / unitDivider, 2);
if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPowerRounded}`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPowerRounded}`);
}
for (let phase = 1; this.chargingStation.getNumberOfPhases() === 3 && phase <= this.chargingStation.getNumberOfPhases(); phase++) {
const phaseValue = `L${phase}-N`;
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
const maxPowerPerPhaseRounded = Utils.roundTo(maxPowerPerPhase / unitDivider, 2);
if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > maxPowerPerPhaseRounded || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxPowerPerPhaseRounded}`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxPowerPerPhaseRounded}`);
}
}
}
: Utils.getRandomFloatRounded(maxAmperage);
break;
default:
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
}
meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases));
const sampledValuesIndex = meterValue.sampledValue.length - 1;
if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxAmperage || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxAmperage}`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxAmperage}`);
}
for (let phase = 1; this.chargingStation.getNumberOfPhases() === 3 && phase <= this.chargingStation.getNumberOfPhases(); phase++) {
const phaseValue = `L${phase}`;
currentMeasurandValues[phaseValue], null, phaseValue as OCPP16MeterValuePhase));
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > maxAmperage || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxAmperage}`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxAmperage}`);
}
}
}
Utils.roundTo(this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) / unitDivider, 2)));
const sampledValuesIndex = meterValue.sampledValue.length - 1;
if (energyValueRounded > maxEnergyRounded || debug) {
- getLogger().error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${energyValueRounded}/${maxEnergyRounded}, duration: ${Utils.roundTo(interval / (3600 * 1000), 4)}h`);
+ logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${energyValueRounded}/${maxEnergyRounded}, duration: ${Utils.roundTo(interval / (3600 * 1000), 4)}h`);
}
}
const payload: MeterValuesRequest = {
import OCPPResponseService from '../OCPPResponseService';
import { ResponseHandler } from '../../../types/ocpp/Responses';
import Utils from '../../../utils/Utils';
-import getLogger from '../../../utils/Logger';
+import logger from '../../../utils/Logger';
export default class OCPP16ResponseService extends OCPPResponseService {
private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
- constructor(chargingStation: ChargingStation) {
+ public constructor(chargingStation: ChargingStation) {
+ if (new.target?.name === 'OCPP16ResponseService') {
+ throw new TypeError('Cannot construct OCPP16ResponseService instances directly');
+ }
super(chargingStation);
this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
[OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
try {
await this.responseHandlers.get(commandName)(payload, requestPayload);
} catch (error) {
- getLogger().error(this.chargingStation.logPrefix() + ' Handle request response error: %j', error);
+ logger.error(this.chargingStation.logPrefix() + ' Handle request response error: %j', error);
throw error;
}
} else {
}
if (Object.values(OCPP16RegistrationStatus).includes(payload.status)) {
const logMsg = `${this.chargingStation.logPrefix()} Charging station in '${payload.status}' state on the central server`;
- payload.status === OCPP16RegistrationStatus.REJECTED ? getLogger().warn(logMsg) : getLogger().info(logMsg);
+ payload.status === OCPP16RegistrationStatus.REJECTED ? logger.warn(logMsg) : logger.info(logMsg);
} else {
- getLogger().error(this.chargingStation.logPrefix() + ' Charging station boot notification response received: %j with undefined registration status', payload);
+ logger.error(this.chargingStation.logPrefix() + ' Charging station boot notification response received: %j with undefined registration status', payload);
}
}
private handleResponseHeartbeat(payload: HeartbeatResponse, requestPayload: HeartbeatRequest): void {
- getLogger().debug(this.chargingStation.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload);
+ logger.debug(this.chargingStation.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload);
}
private handleResponseAuthorize(payload: OCPP16AuthorizeResponse, requestPayload: AuthorizeRequest): void {
}
if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true;
- getLogger().debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`);
+ logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`);
} else {
this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
delete this.chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag;
- getLogger().debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`);
+ logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`);
}
}
}
}
if (!transactionConnectorId) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString());
return;
}
if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
&& this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not local authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not local authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
await this.resetConnectorOnStartTransactionError(connectorId);
return;
}
if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
&& this.chargingStation.getMayAuthorizeAtRemoteStart() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
&& !this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
await this.resetConnectorOnStartTransactionError(connectorId);
return;
}
if (this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized && this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the authorize request one ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the authorize request one ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
await this.resetConnectorOnStartTransactionError(connectorId);
return;
}
if (this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
&& this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== requestPayload.idTag) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the local authorized one ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the local authorized one ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
await this.resetConnectorOnStartTransactionError(connectorId);
return;
}
if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
- getLogger().debug(this.chargingStation.logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId.toString() + ': %j', this.chargingStation.getConnectorStatus(connectorId));
+ logger.debug(this.chargingStation.logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId.toString() + ': %j', this.chargingStation.getConnectorStatus(connectorId));
return;
}
if (this.chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.AVAILABLE
&& this.chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING) {
- getLogger().error(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${this.chargingStation.getConnectorStatus(connectorId)?.status}`);
+ logger.error(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${this.chargingStation.getConnectorStatus(connectorId)?.status}`);
return;
}
if (!Number.isInteger(payload.transactionId)) {
- getLogger().warn(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${payload.transactionId}, converting to integer`);
+ logger.warn(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${payload.transactionId}, converting to integer`);
payload.transactionId = Utils.convertToInt(payload.transactionId);
}
this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue);
await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.CHARGING);
this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.CHARGING;
- getLogger().info(this.chargingStation.logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag);
+ logger.info(this.chargingStation.logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag);
if (this.chargingStation.stationInfo.powerSharedByConnectors) {
this.chargingStation.stationInfo.powerDivider++;
}
const configuredMeterValueSampleInterval = this.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValueSampleInterval);
this.chargingStation.startMeterValues(connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
} else {
- getLogger().warn(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
+ logger.warn(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
await this.resetConnectorOnStartTransactionError(connectorId);
}
}
}
}
if (!transactionConnectorId) {
- getLogger().error(this.chargingStation.logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId.toString());
+ logger.error(this.chargingStation.logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId.toString());
return;
}
if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
if (this.chargingStation.stationInfo.powerSharedByConnectors) {
this.chargingStation.stationInfo.powerDivider--;
}
- getLogger().info(this.chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString());
+ logger.info(this.chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString());
this.chargingStation.resetConnectorStatus(transactionConnectorId);
} else {
- getLogger().warn(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
+ logger.warn(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
}
}
private handleResponseStatusNotification(payload: StatusNotificationRequest, requestPayload: StatusNotificationResponse): void {
- getLogger().debug(this.chargingStation.logPrefix() + ' Status notification response received: %j to StatusNotification request: %j', payload, requestPayload);
+ logger.debug(this.chargingStation.logPrefix() + ' Status notification response received: %j to StatusNotification request: %j', payload, requestPayload);
}
private handleResponseMeterValues(payload: MeterValuesRequest, requestPayload: MeterValuesResponse): void {
- getLogger().debug(this.chargingStation.logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload, requestPayload);
+ logger.debug(this.chargingStation.logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload, requestPayload);
}
}
import { RequestCommand } from '../../../types/ocpp/Requests';
import { SampledValueTemplate } from '../../../types/MeasurandPerPhaseSampledValueTemplates';
import Utils from '../../../utils/Utils';
-import getLogger from '../../../utils/Logger';
+import logger from '../../../utils/Logger';
export class OCPP16ServiceUtils {
public static checkMeasurandPowerDivider(chargingStation: ChargingStation, measurandType: OCPP16MeterValueMeasurand): void {
if (Utils.isUndefined(chargingStation.stationInfo.powerDivider)) {
const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
} else if (chargingStation.stationInfo?.powerDivider <= 0) {
const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
- getLogger().error(errMsg);
+ logger.error(errMsg);
throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
}
}
-import ChargingStation from '../ChargingStation';
+import type ChargingStation from '../ChargingStation';
import { IncomingRequestCommand } from '../../types/ocpp/Requests';
import { JsonType } from '../../types/JsonType';
-import getLogger from '../../utils/Logger';
+import logger from '../../utils/Logger';
export default abstract class OCPPIncomingRequestService {
+ private static readonly instances: Map<string, OCPPIncomingRequestService> = new Map<string, OCPPIncomingRequestService>();
protected chargingStation: ChargingStation;
- constructor(chargingStation: ChargingStation) {
+ protected constructor(chargingStation: ChargingStation) {
this.chargingStation = chargingStation;
}
+ public static getInstance<T extends OCPPIncomingRequestService>(this: new (chargingStation: ChargingStation) => T, chargingStation: ChargingStation): T {
+ if (!OCPPIncomingRequestService.instances.has(chargingStation.id)) {
+ OCPPIncomingRequestService.instances.set(chargingStation.id, new this(chargingStation));
+ }
+ return OCPPIncomingRequestService.instances.get(chargingStation.id) as T;
+ }
+
protected handleIncomingRequestError<T>(commandName: IncomingRequestCommand, error: Error, errorOcppResponse?: T): T {
- getLogger().error(this.chargingStation.logPrefix() + ' Incoming request command %s error: %j', commandName, error);
+ logger.error(this.chargingStation.logPrefix() + ' Incoming request command %s error: %j', commandName, error);
if (errorOcppResponse) {
return errorOcppResponse;
}
import { BootNotificationResponse } from '../../types/ocpp/Responses';
import { ChargePointErrorCode } from '../../types/ocpp/ChargePointErrorCode';
import { ChargePointStatus } from '../../types/ocpp/ChargePointStatus';
-import ChargingStation from '../ChargingStation';
+import type ChargingStation from '../ChargingStation';
import Constants from '../../utils/Constants';
import { ErrorType } from '../../types/ocpp/ErrorType';
import { JsonType } from '../../types/JsonType';
import { MessageType } from '../../types/ocpp/MessageType';
import { MeterValue } from '../../types/ocpp/MeterValues';
import OCPPError from '../../exception/OCPPError';
-import OCPPResponseService from './OCPPResponseService';
+import type OCPPResponseService from './OCPPResponseService';
import PerformanceStatistics from '../../performance/PerformanceStatistics';
import Utils from '../../utils/Utils';
-import getLogger from '../../utils/Logger';
+import logger from '../../utils/Logger';
export default abstract class OCPPRequestService {
- public chargingStation: ChargingStation;
- protected ocppResponseService: OCPPResponseService;
+ private static readonly instances: Map<string, OCPPRequestService> = new Map<string, OCPPRequestService>();
+ protected readonly chargingStation: ChargingStation;
+ private readonly ocppResponseService: OCPPResponseService;
- constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) {
+ protected constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) {
this.chargingStation = chargingStation;
this.ocppResponseService = ocppResponseService;
}
- public async sendMessage(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand,
+ public static getInstance<T extends OCPPRequestService>(this: new (chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) => T, chargingStation: ChargingStation, ocppResponseService: OCPPResponseService): T {
+ if (!OCPPRequestService.instances.has(chargingStation.id)) {
+ OCPPRequestService.instances.set(chargingStation.id, new this(chargingStation, ocppResponseService));
+ }
+ return OCPPRequestService.instances.get(chargingStation.id) as T;
+ }
+
+ protected async sendMessage(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand,
params: SendParams = {
skipBufferingOnError: false,
triggerMessage: false
if (requestStatistic && self.chargingStation.getEnableStatistics()) {
self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_ERROR_MESSAGE);
}
- getLogger().error(`${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, error, commandName, messageData);
+ logger.error(`${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, error, commandName, messageData);
self.chargingStation.requests.delete(messageId);
reject(error);
}
}
protected handleRequestError(commandName: RequestCommand, error: Error): void {
- getLogger().error(this.chargingStation.logPrefix() + ' Request command %s error: %j', commandName, error);
+ logger.error(this.chargingStation.logPrefix() + ' Request command %s error: %j', commandName, error);
throw error;
}
-import ChargingStation from '../ChargingStation';
+import type ChargingStation from '../ChargingStation';
import { JsonType } from '../../types/JsonType';
import { RequestCommand } from '../../types/ocpp/Requests';
export default abstract class OCPPResponseService {
- protected chargingStation: ChargingStation;
+ private static readonly instances: Map<string, OCPPResponseService> = new Map<string, OCPPResponseService>();
+ protected readonly chargingStation: ChargingStation;
- constructor(chargingStation: ChargingStation) {
+ protected constructor(chargingStation: ChargingStation) {
this.chargingStation = chargingStation;
}
+ public static getInstance<T extends OCPPResponseService>(this: new (chargingStation: ChargingStation) => T, chargingStation: ChargingStation): T {
+ if (!OCPPResponseService.instances.has(chargingStation.id)) {
+ OCPPResponseService.instances.set(chargingStation.id, new this(chargingStation));
+ }
+ return OCPPResponseService.instances.get(chargingStation.id) as T;
+ }
+
public abstract handleResponse(commandName: RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise<void>;
}
import BaseError from '../../exception/BaseError';
import { JsonType } from '../../types/JsonType';
import UIWebSocketServer from '../UIWebSocketServer';
-import getLogger from '../../utils/Logger';
+import logger from '../../utils/Logger';
export default abstract class AbstractUIService {
protected readonly uiWebSocketServer: UIWebSocketServer;
messageResponse = await this.messageHandlers.get(command)(payload) as JsonType;
} catch (error) {
// Log
- getLogger().error(this.uiWebSocketServer.logPrefix() + ' Handle message error: %j', error);
+ logger.error(this.uiWebSocketServer.logPrefix() + ' Handle message error: %j', error);
throw error;
}
} else {
import { IncomingMessage } from 'http';
import Utils from '../../utils/Utils';
-import getLogger from '../../utils/Logger';
+import logger from '../../utils/Logger';
export class UIServiceUtils {
public static handleProtocols = (protocols: Set<string>, request: IncomingMessage): string | false => {
return fullProtocol;
}
}
- getLogger().error(`${Utils.logPrefix(' UI WebSocket Server:')} Unsupported protocol: ${protocol} or protocol version: ${version}`);
+ logger.error(`${Utils.logPrefix(' UI WebSocket Server:')} Unsupported protocol: ${protocol} or protocol version: ${version}`);
return false;
};
}
import { MessageType } from '../types/ocpp/MessageType';
import { URL } from 'url';
import Utils from '../utils/Utils';
-import getLogger from '../utils/Logger';
+import logger from '../utils/Logger';
import { parentPort } from 'worker_threads';
export default class PerformanceStatistics {
+ private static readonly instances: Map<string, PerformanceStatistics> = new Map<string, PerformanceStatistics>();
private readonly objId: string;
+ private readonly objName: string;
private performanceObserver: PerformanceObserver;
private readonly statistics: Statistics;
private displayInterval: NodeJS.Timeout;
- public constructor(objId: string, uri: URL) {
+ private constructor(objId: string, objName: string, uri: URL) {
this.objId = objId;
+ this.objName = objName;
this.initializePerformanceObserver();
- this.statistics = { id: this.objId ?? 'Object id not specified', uri: uri.toString(), createdAt: new Date(), statisticsData: new Map<string, Partial<StatisticsData>>() };
+ this.statistics = { id: this.objId ?? 'Object id not specified', name: this.objName ?? 'Object name not specified', uri: uri.toString(), createdAt: new Date(), statisticsData: new Map<string, Partial<StatisticsData>>() };
+ }
+
+ public static getInstance(objId: string, objName: string, uri: URL): PerformanceStatistics {
+ if (!PerformanceStatistics.instances.has(objId)) {
+ PerformanceStatistics.instances.set(objId, new PerformanceStatistics(objId, objName, uri));
+ }
+ return PerformanceStatistics.instances.get(objId);
}
public static beginMeasure(id: string): string {
}
break;
default:
- getLogger().error(`${this.logPrefix()} wrong message type ${messageType}`);
+ logger.error(`${this.logPrefix()} wrong message type ${messageType}`);
break;
}
}
public start(): void {
this.startLogStatisticsInterval();
if (Configuration.getPerformanceStorage().enabled) {
- getLogger().info(`${this.logPrefix()} storage enabled: type ${Configuration.getPerformanceStorage().type}, uri: ${Configuration.getPerformanceStorage().uri}`);
+ logger.info(`${this.logPrefix()} storage enabled: type ${Configuration.getPerformanceStorage().type}, uri: ${Configuration.getPerformanceStorage().uri}`);
}
}
this.performanceObserver = new PerformanceObserver((list) => {
const lastPerformanceEntry = list.getEntries()[0];
this.addPerformanceEntryToStatistics(lastPerformanceEntry);
- getLogger().debug(`${this.logPrefix()} '${lastPerformanceEntry.name}' performance entry: %j`, lastPerformanceEntry);
+ logger.debug(`${this.logPrefix()} '${lastPerformanceEntry.name}' performance entry: %j`, lastPerformanceEntry);
});
this.performanceObserver.observe({ entryTypes: ['measure'] });
}
private logStatistics(): void {
- getLogger().info(this.logPrefix() + ' %j', this.statistics);
+ logger.info(this.logPrefix() + ' %j', this.statistics);
}
private startLogStatisticsInterval(): void {
this.displayInterval = setInterval(() => {
this.logStatistics();
}, Configuration.getLogStatisticsInterval() * 1000);
- getLogger().info(this.logPrefix() + ' logged every ' + Utils.formatDurationSeconds(Configuration.getLogStatisticsInterval()));
+ logger.info(this.logPrefix() + ' logged every ' + Utils.formatDurationSeconds(Configuration.getLogStatisticsInterval()));
} else {
- getLogger().info(this.logPrefix() + ' log interval is set to ' + Configuration.getLogStatisticsInterval().toString() + '. Not logging statistics');
+ logger.info(this.logPrefix() + ' log interval is set to ' + Configuration.getLogStatisticsInterval().toString() + '. Not logging statistics');
}
}
}
private logPrefix(): string {
- return Utils.logPrefix(` ${this.objId} | Performance statistics`);
+ return Utils.logPrefix(` ${this.objName} | Performance statistics`);
}
}
import Statistics from '../../types/Statistics';
import { URL } from 'url';
import Utils from '../../utils/Utils';
-import getLogger from '../../utils/Logger';
+import logger from '../../utils/Logger';
export abstract class Storage {
protected readonly storageUri: URL;
}
protected handleDBError(type: StorageType, error: Error, table?: string): void {
- getLogger().error(`${this.logPrefix} ${this.getDBNameFromStorageType(type)} error '${error.message}'${(!Utils.isNullOrUndefined(table) || !table) && ` in table or collection '${table}'`}: %j`, error);
+ logger.error(`${this.logPrefix} ${this.getDBNameFromStorageType(type)} error '${error.message}'${(!Utils.isNullOrUndefined(table) || !table) && ` in table or collection '${table}'`}: %j`, error);
}
protected getDBNameFromStorageType(type: StorageType): DBName {
export default interface Statistics {
id: string;
+ name: string;
uri: string;
createdAt: Date;
updatedAt?: Date;
import chalk from 'chalk';
-import getLogger from './Logger';
+import logger from './Logger';
export default class FileUtils {
static handleFileException(logPrefix: string, fileType: string, filePath: string, error: NodeJS.ErrnoException, consoleOut = false): void {
if (consoleOut) {
console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' not found: '), error);
} else {
- getLogger().warn(prefix + fileType + ' file ' + filePath + ' not found: %j', error);
+ logger.warn(prefix + fileType + ' file ' + filePath + ' not found: %j', error);
}
} else if (error.code === 'EEXIST') {
if (consoleOut) {
console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' already exists: '), error);
} else {
- getLogger().warn(prefix + fileType + ' file ' + filePath + ' already exists: %j', error);
+ logger.warn(prefix + fileType + ' file ' + filePath + ' already exists: %j', error);
}
} else if (error.code === 'EACCES') {
if (consoleOut) {
console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' access denied: '), error);
} else {
- getLogger().warn(prefix + fileType + ' file ' + filePath + ' access denied: %j', error);
+ logger.warn(prefix + fileType + ' file ' + filePath + ' access denied: %j', error);
}
} else {
if (consoleOut) {
console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' error: '), error);
} else {
- getLogger().warn(prefix + fileType + ' file ' + filePath + ' error: %j', error);
+ logger.warn(prefix + fileType + ' file ' + filePath + ' error: %j', error);
}
throw error;
}
];
}
-let loggerInstance: Logger | null = null;
-const getLogger = (): Logger => {
- if (!loggerInstance) {
- loggerInstance = createLogger({
- level: Configuration.getLogLevel(),
- format: format.combine(format.splat(), format[Configuration.getLogFormat()]()),
- transports: transports,
- });
- return loggerInstance;
- }
-};
+const logger: Logger = createLogger({
+ level: Configuration.getLogLevel(),
+ format: format.combine(format.splat(), format[Configuration.getLogFormat()]()),
+ transports: transports,
+});
//
// If enabled, log to the `console` with the format:
// `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
//
if (Configuration.getLogConsole()) {
- getLogger().add(new Console({
+ logger.add(new Console({
format: format.combine(format.splat(), format[Configuration.getLogFormat()]()),
}));
}
-export default getLogger;
+export default logger;