X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcharging-station%2FChargingStation.ts;h=f351261029c74a6fac12aaff5055cdd4400874fc;hb=a979cc125b0c038fa70376f62b507d5dbd9604da;hp=83074dd7e9f23516e831bc0845ae154736032666;hpb=6af9012e5b9ef2ed6f4fe8a9696b40ac0e8da4d0;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 83074dd7..f3512610 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -15,24 +15,24 @@ import logger from '../utils/Logger'; export default class ChargingStation { private _index: number; - private _stationTemplateFile; + private _stationTemplateFile: string; private _stationInfo; private _bootNotificationMessage; private _connectors; private _configuration; - private _connectorsConfigurationHash; + private _connectorsConfigurationHash: string; private _supervisionUrl; private _wsConnectionUrl; - private _wsConnection; + private _wsConnection: WebSocket; private _isSocketRestart; - private _autoReconnectRetryCount; - private _autoReconnectMaxRetries; - private _autoReconnectTimeout; + private _autoReconnectRetryCount: number; + private _autoReconnectMaxRetries: number; + private _autoReconnectTimeout: number; private _requests; private _messageQueue; private _automaticTransactionGeneration: AutomaticTransactionGenerator; private _authorizedTags: string[]; - private _heartbeatInterval; + private _heartbeatInterval: number; private _heartbeatSetInterval; private _statistics: Statistics; private _performanceObserver: PerformanceObserver; @@ -303,19 +303,19 @@ export default class ChargingStation { return localAuthListEnabled ? Utils.convertToBoolean(localAuthListEnabled.value) : false; } - _basicStartMessageSequence(): void { + _startMessageSequence(): void { // Start heartbeat this._startHeartbeat(); // Initialize connectors status for (const connector in this._connectors) { if (!this.getConnector(Utils.convertToInt(connector)).transactionStarted) { if (this.getConnector(Utils.convertToInt(connector)).bootStatus) { - this.sendStatusNotificationWithTimeout(connector, this.getConnector(Utils.convertToInt(connector)).bootStatus); + this.sendStatusNotification(Utils.convertToInt(connector), this.getConnector(Utils.convertToInt(connector)).bootStatus); } else { - this.sendStatusNotificationWithTimeout(connector, 'Available'); + this.sendStatusNotification(Utils.convertToInt(connector), 'Available'); } } else { - this.sendStatusNotificationWithTimeout(connector, 'Charging'); + this.sendStatusNotification(Utils.convertToInt(connector), 'Charging'); } } // Start the ATG @@ -332,6 +332,23 @@ export default class ChargingStation { } } + async _stopMessageSequence(reason = ''): Promise { + // Stop heartbeat + this._stopHeartbeat(); + // Stop the ATG + if (Utils.convertToBoolean(this._stationInfo.AutomaticTransactionGenerator.enable) && + this._automaticTransactionGeneration && + !this._automaticTransactionGeneration.timeToStop) { + await this._automaticTransactionGeneration.stop(reason); + } else { + for (const connector in this._connectors) { + if (this.getConnector(Utils.convertToInt(connector)).transactionStarted) { + await this.sendStopTransaction(this.getConnector(Utils.convertToInt(connector)).transactionId, reason); + } + } + } + } + _startHeartbeat(): void { if (this._heartbeatInterval && this._heartbeatInterval > 0 && !this._heartbeatSetInterval) { this._heartbeatSetInterval = setInterval(() => { @@ -370,8 +387,10 @@ export default class ChargingStation { logger.debug(this._logPrefix() + ' Template file ' + this._stationTemplateFile + ' have changed, reload'); // Initialize this._initialize(); - this._addConfigurationKey('HeartBeatInterval', Utils.convertToInt(this._heartbeatInterval ? this._heartbeatInterval / 1000 : 0)); - this._addConfigurationKey('HeartbeatInterval', Utils.convertToInt(this._heartbeatInterval ? this._heartbeatInterval / 1000 : 0), false, false); + if (!Utils.convertToBoolean(this._stationInfo.AutomaticTransactionGenerator.enable) && + this._automaticTransactionGeneration) { + this._automaticTransactionGeneration.stop().catch(() => {}); + } } catch (error) { logger.error(this._logPrefix() + ' Charging station template file monitoring error: ' + error); } @@ -388,14 +407,16 @@ export default class ChargingStation { } if (interval > 0) { this.getConnector(connectorId).transactionSetInterval = setInterval(async () => { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; if (this.getEnableStatistics()) { const sendMeterValues = performance.timerify(this.sendMeterValues); this._performanceObserver.observe({ entryTypes: ['function'], }); - await sendMeterValues(connectorId, interval); + await sendMeterValues(connectorId, interval, self); } else { - await this.sendMeterValues(connectorId, interval); + await this.sendMeterValues(connectorId, interval, self); } }, interval); } else { @@ -426,20 +447,8 @@ export default class ChargingStation { } async stop(reason = '') { - // Stop heartbeat - this._stopHeartbeat(); - // Stop the ATG - if (Utils.convertToBoolean(this._stationInfo.AutomaticTransactionGenerator.enable) && - this._automaticTransactionGeneration && - !this._automaticTransactionGeneration.timeToStop) { - await this._automaticTransactionGeneration.stop(reason); - } else { - for (const connector in this._connectors) { - if (this.getConnector(Utils.convertToInt(connector)).transactionStarted) { - await this.sendStopTransaction(this.getConnector(Utils.convertToInt(connector)).transactionId, reason); - } - } - } + // Stop + await this._stopMessageSequence(); // eslint-disable-next-line guard-for-in for (const connector in this._connectors) { await this.sendStatusNotification(Utils.convertToInt(connector), 'Unavailable'); @@ -480,7 +489,7 @@ export default class ChargingStation { this.sendBootNotification(); } if (this._isSocketRestart) { - this._basicStartMessageSequence(); + this._startMessageSequence(); if (!Utils.isEmptyArray(this._messageQueue)) { this._messageQueue.forEach((message) => { if (this._wsConnection && this._wsConnection.readyState === WebSocket.OPEN) { @@ -548,7 +557,7 @@ export default class ChargingStation { } if (!responseCallback) { // Error - throw new Error(`Response for unknown message id ${messageId}`); + throw new Error(`Response request for unknown message id ${messageId}`); } delete this._requests[messageId]; responseCallback(commandName, requestPayload); @@ -557,7 +566,7 @@ export default class ChargingStation { case Constants.OCPP_JSON_CALL_ERROR_MESSAGE: if (!this._requests[messageId]) { // Error - throw new Error(`Error for unknown message id ${messageId}`); + throw new Error(`Error request for unknown message id ${messageId}`); } // eslint-disable-next-line no-case-declarations let rejectCallback; @@ -577,7 +586,7 @@ export default class ChargingStation { // Log logger.error('%s Incoming message %j processing error %s on request content %s', this._logPrefix(), message, error, this._requests[messageId]); // Send error - // await this.sendError(messageId, error); + await this.sendError(messageId, error); } } @@ -616,15 +625,11 @@ export default class ChargingStation { } } - sendStatusNotificationWithTimeout(connectorId, status, errorCode = 'NoError', timeout = Constants.STATUS_NOTIFICATION_TIMEOUT) { - setTimeout(async () => this.sendStatusNotification(connectorId, status, errorCode), timeout); - } - async sendStartTransaction(connectorId: number, idTag?: string) { try { const payload = { connectorId, - ...!Utils.isUndefined(idTag) && { idTag }, + ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: '' }, meterStart: 0, timestamp: new Date().toISOString(), }; @@ -635,10 +640,6 @@ export default class ChargingStation { } } - sendStartTransactionWithTimeout(connectorId: number, idTag?: string, timeout = Constants.START_TRANSACTION_TIMEOUT) { - setTimeout(async () => this.sendStartTransaction(connectorId, idTag), timeout); - } - async sendStopTransaction(transactionId, reason = ''): Promise { try { const payload = { @@ -654,17 +655,18 @@ export default class ChargingStation { } } - async sendMeterValues(connectorId, interval, debug = false): Promise { + // eslint-disable-next-line consistent-this + async sendMeterValues(connectorId: number, interval: number, self, debug = false): Promise { try { const sampledValues = { timestamp: new Date().toISOString(), sampledValue: [], }; - const meterValuesTemplate = this.getConnector(connectorId).MeterValues; + const meterValuesTemplate = self.getConnector(connectorId).MeterValues; for (let index = 0; index < meterValuesTemplate.length; index++) { - const connector = this.getConnector(connectorId); + const connector = self.getConnector(connectorId); // SoC measurand - if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'SoC' && this._getConfigurationKey('MeterValuesSampledData').value.includes('SoC')) { + if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'SoC' && self._getConfigurationKey('MeterValuesSampledData').value.includes('SoC')) { sampledValues.sampledValue.push({ ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: 'Percent' }, ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, @@ -674,57 +676,57 @@ export default class ChargingStation { }); const sampledValuesIndex = sampledValues.sampledValue.length - 1; if (sampledValues.sampledValue[sampledValuesIndex].value > 100 || debug) { - logger.error(`${this._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/100`); + logger.error(`${self._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/100`); } // Voltage measurand - } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Voltage' && this._getConfigurationKey('MeterValuesSampledData').value.includes('Voltage')) { + } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Voltage' && self._getConfigurationKey('MeterValuesSampledData').value.includes('Voltage')) { sampledValues.sampledValue.push({ ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: 'V' }, ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, measurand: meterValuesTemplate[index].measurand, ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: this._getVoltageOut() }, + ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: self._getVoltageOut() }, }); - for (let phase = 1; this._getNumberOfPhases() === 3 && phase <= this._getNumberOfPhases(); phase++) { + for (let phase = 1; self._getNumberOfPhases() === 3 && phase <= self._getNumberOfPhases(); phase++) { const voltageValue = sampledValues.sampledValue[sampledValues.sampledValue.length - 1].value; let phaseValue; if (voltageValue >= 0 && voltageValue <= 250) { phaseValue = `L${phase}-N`; } else if (voltageValue > 250) { - phaseValue = `L${phase}-L${(phase + 1) % this._getNumberOfPhases() !== 0 ? (phase + 1) % this._getNumberOfPhases() : this._getNumberOfPhases()}`; + phaseValue = `L${phase}-L${(phase + 1) % self._getNumberOfPhases() !== 0 ? (phase + 1) % self._getNumberOfPhases() : self._getNumberOfPhases()}`; } sampledValues.sampledValue.push({ ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: 'V' }, ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, measurand: meterValuesTemplate[index].measurand, ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: this._getVoltageOut() }, + ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: self._getVoltageOut() }, phase: phaseValue, }); } // Power.Active.Import measurand - } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Power.Active.Import' && this._getConfigurationKey('MeterValuesSampledData').value.includes('Power.Active.Import')) { + } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Power.Active.Import' && self._getConfigurationKey('MeterValuesSampledData').value.includes('Power.Active.Import')) { // FIXME: factor out powerDivider checks - if (Utils.isUndefined(this._stationInfo.powerDivider)) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; + if (Utils.isUndefined(self._stationInfo.powerDivider)) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; logger.error(errMsg); throw Error(errMsg); - } else if (this._stationInfo.powerDivider && this._stationInfo.powerDivider <= 0) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${this._stationInfo.powerDivider}`; + } else if (self._stationInfo.powerDivider && self._stationInfo.powerDivider <= 0) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${self._stationInfo.powerDivider}`; logger.error(errMsg); throw Error(errMsg); } - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: Unknown ${this._getPowerOutType()} powerOutType in template file ${this._stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} measurand value`; + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: Unknown ${self._getPowerOutType()} powerOutType in template file ${self._stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} measurand value`; const powerMeasurandValues = {} as MeasurandValues ; - const maxPower = Math.round(this._stationInfo.maxPower / this._stationInfo.powerDivider); - const maxPowerPerPhase = Math.round((this._stationInfo.maxPower / this._stationInfo.powerDivider) / this._getNumberOfPhases()); - switch (this._getPowerOutType()) { + const maxPower = Math.round(self._stationInfo.maxPower / self._stationInfo.powerDivider); + const maxPowerPerPhase = Math.round((self._stationInfo.maxPower / self._stationInfo.powerDivider) / self._getNumberOfPhases()); + switch (self._getPowerOutType()) { case 'AC': if (Utils.isUndefined(meterValuesTemplate[index].value)) { powerMeasurandValues.L1 = Utils.getRandomFloatRounded(maxPowerPerPhase); powerMeasurandValues.L2 = 0; powerMeasurandValues.L3 = 0; - if (this._getNumberOfPhases() === 3) { + if (self._getNumberOfPhases() === 3) { powerMeasurandValues.L2 = Utils.getRandomFloatRounded(maxPowerPerPhase); powerMeasurandValues.L3 = Utils.getRandomFloatRounded(maxPowerPerPhase); } @@ -749,9 +751,9 @@ export default class ChargingStation { }); const sampledValuesIndex = sampledValues.sampledValue.length - 1; if (sampledValues.sampledValue[sampledValuesIndex].value > maxPower || debug) { - logger.error(`${this._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxPower}`); + logger.error(`${self._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxPower}`); } - for (let phase = 1; this._getNumberOfPhases() === 3 && phase <= this._getNumberOfPhases(); phase++) { + for (let phase = 1; self._getNumberOfPhases() === 3 && phase <= self._getNumberOfPhases(); phase++) { const phaseValue = `L${phase}-N`; sampledValues.sampledValue.push({ ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: 'W' }, @@ -763,36 +765,36 @@ export default class ChargingStation { }); } // Current.Import measurand - } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Current.Import' && this._getConfigurationKey('MeterValuesSampledData').value.includes('Current.Import')) { + } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === 'Current.Import' && self._getConfigurationKey('MeterValuesSampledData').value.includes('Current.Import')) { // FIXME: factor out powerDivider checks - if (Utils.isUndefined(this._stationInfo.powerDivider)) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; + if (Utils.isUndefined(self._stationInfo.powerDivider)) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; logger.error(errMsg); throw Error(errMsg); - } else if (this._stationInfo.powerDivider && this._stationInfo.powerDivider <= 0) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${this._stationInfo.powerDivider}`; + } else if (self._stationInfo.powerDivider && self._stationInfo.powerDivider <= 0) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${self._stationInfo.powerDivider}`; logger.error(errMsg); throw Error(errMsg); } - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: Unknown ${this._getPowerOutType()} powerOutType in template file ${this._stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} measurand value`; + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: Unknown ${self._getPowerOutType()} powerOutType in template file ${self._stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} measurand value`; const currentMeasurandValues = {} as MeasurandValues; let maxAmperage; - switch (this._getPowerOutType()) { + switch (self._getPowerOutType()) { case 'AC': - maxAmperage = ElectricUtils.ampPerPhaseFromPower(this._getNumberOfPhases(), this._stationInfo.maxPower / this._stationInfo.powerDivider, this._getVoltageOut()); + maxAmperage = ElectricUtils.ampPerPhaseFromPower(self._getNumberOfPhases(), self._stationInfo.maxPower / self._stationInfo.powerDivider, self._getVoltageOut()); if (Utils.isUndefined(meterValuesTemplate[index].value)) { currentMeasurandValues.L1 = Utils.getRandomFloatRounded(maxAmperage); currentMeasurandValues.L2 = 0; currentMeasurandValues.L3 = 0; - if (this._getNumberOfPhases() === 3) { + if (self._getNumberOfPhases() === 3) { currentMeasurandValues.L2 = Utils.getRandomFloatRounded(maxAmperage); currentMeasurandValues.L3 = Utils.getRandomFloatRounded(maxAmperage); } - currentMeasurandValues.all = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / this._getNumberOfPhases(), 2); + currentMeasurandValues.all = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / self._getNumberOfPhases(), 2); } break; case 'DC': - maxAmperage = ElectricUtils.ampTotalFromPower(this._stationInfo.maxPower / this._stationInfo.powerDivider, this._getVoltageOut()); + maxAmperage = ElectricUtils.ampTotalFromPower(self._stationInfo.maxPower / self._stationInfo.powerDivider, self._getVoltageOut()); if (Utils.isUndefined(meterValuesTemplate[index].value)) { currentMeasurandValues.all = Utils.getRandomFloatRounded(maxAmperage); } @@ -810,9 +812,9 @@ export default class ChargingStation { }); const sampledValuesIndex = sampledValues.sampledValue.length - 1; if (sampledValues.sampledValue[sampledValuesIndex].value > maxAmperage || debug) { - logger.error(`${this._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxAmperage}`); + logger.error(`${self._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxAmperage}`); } - for (let phase = 1; this._getNumberOfPhases() === 3 && phase <= this._getNumberOfPhases(); phase++) { + for (let phase = 1; self._getNumberOfPhases() === 3 && phase <= self._getNumberOfPhases(); phase++) { const phaseValue = `L${phase}`; sampledValues.sampledValue.push({ ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: 'A' }, @@ -826,17 +828,17 @@ export default class ChargingStation { // Energy.Active.Import.Register measurand (default) } else if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === 'Energy.Active.Import.Register') { // FIXME: factor out powerDivider checks - if (Utils.isUndefined(this._stationInfo.powerDivider)) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; + if (Utils.isUndefined(self._stationInfo.powerDivider)) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider is undefined`; logger.error(errMsg); throw Error(errMsg); - } else if (this._stationInfo.powerDivider && this._stationInfo.powerDivider <= 0) { - const errMsg = `${this._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${this._stationInfo.powerDivider}`; + } else if (self._stationInfo.powerDivider && self._stationInfo.powerDivider <= 0) { + const errMsg = `${self._logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'}: powerDivider have zero or below value ${self._stationInfo.powerDivider}`; logger.error(errMsg); throw Error(errMsg); } if (Utils.isUndefined(meterValuesTemplate[index].value)) { - const measurandValue = Utils.getRandomInt(this._stationInfo.maxPower / (this._stationInfo.powerDivider * 3600000) * interval); + const measurandValue = Utils.getRandomInt(self._stationInfo.maxPower / (self._stationInfo.powerDivider * 3600000) * interval); // Persist previous value in connector if (connector && !Utils.isNullOrUndefined(connector.lastEnergyActiveImportRegisterValue) && connector.lastEnergyActiveImportRegisterValue >= 0) { connector.lastEnergyActiveImportRegisterValue += measurandValue; @@ -852,24 +854,24 @@ export default class ChargingStation { ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: connector.lastEnergyActiveImportRegisterValue }, }); const sampledValuesIndex = sampledValues.sampledValue.length - 1; - const maxConsumption = Math.round(this._stationInfo.maxPower * 3600 / (this._stationInfo.powerDivider * interval)); + const maxConsumption = Math.round(self._stationInfo.maxPower * 3600 / (self._stationInfo.powerDivider * interval)); if (sampledValues.sampledValue[sampledValuesIndex].value > maxConsumption || debug) { - logger.error(`${this._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxConsumption}`); + logger.error(`${self._logPrefix()} MeterValues measurand ${sampledValues.sampledValue[sampledValuesIndex].measurand ? sampledValues.sampledValue[sampledValuesIndex].measurand : 'Energy.Active.Import.Register'}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${sampledValues.sampledValue[sampledValuesIndex].value}/${maxConsumption}`); } // Unsupported measurand } else { - logger.info(`${this._logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} on connectorId ${connectorId}`); + logger.info(`${self._logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : 'Energy.Active.Import.Register'} on connectorId ${connectorId}`); } } const payload = { connectorId, - transactionId: this.getConnector(connectorId).transactionId, + transactionId: self.getConnector(connectorId).transactionId, meterValue: sampledValues, }; - await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'MeterValues'); + await self.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'MeterValues'); } catch (error) { - logger.error(this._logPrefix() + ' Send MeterValues error: ' + error); + logger.error(self._logPrefix() + ' Send MeterValues error: ' + error); throw error; } } @@ -910,7 +912,7 @@ export default class ChargingStation { if (this.getEnableStatistics()) { this._statistics.addMessage(`Error ${command.code ? command.code : Constants.OCPP_ERROR_GENERIC_ERROR} on ${commandName}`); } - // Build Message + // Build Error Message messageToSend = JSON.stringify([messageType, messageId, command.code ? command.code : Constants.OCPP_ERROR_GENERIC_ERROR, command.message ? command.message : '', command.details ? command.details : {}]); break; } @@ -921,21 +923,22 @@ export default class ChargingStation { } else { // Buffer message until connection is back this._messageQueue.push(messageToSend); + // Reject it + return rejectCallback(new OCPPError(command.code ? command.code : Constants.OCPP_ERROR_GENERIC_ERROR, command.message ? command.message : `Web socket closed for message id '${messageId}' with content '${messageToSend}', buffer it`, command.details ? command.details : {})); } - // Request? - if (messageType !== Constants.OCPP_JSON_CALL_MESSAGE) { + // Response? + if (messageType === Constants.OCPP_JSON_CALL_RESULT_MESSAGE) { // Yes: send Ok resolve(); - } else if (this._wsConnection && this._wsConnection.readyState === WebSocket.OPEN) { - // Send timeout in case connection is open otherwise wait for ever - // FIXME: Handle message on timeout - setTimeout(() => rejectCallback(new OCPPError(command.code ? command.code : Constants.OCPP_ERROR_GENERIC_ERROR, command.message ? command.message : '', command.details ? command.details : {})), Constants.OCPP_SOCKET_TIMEOUT); + } else if (messageType === Constants.OCPP_JSON_CALL_ERROR_MESSAGE) { + // Send timeout + setTimeout(() => rejectCallback(new OCPPError(command.code ? command.code : Constants.OCPP_ERROR_GENERIC_ERROR, command.message ? command.message : `Timeout for message id '${messageId}' with content '${messageToSend}'`, command.details ? command.details : {})), Constants.OCPP_SOCKET_TIMEOUT); } // Function that will receive the request's response function responseCallback(payload, requestPayload) { - self.handleResponse(commandName, payload, requestPayload); // Send the response + self.handleResponse(commandName, payload, requestPayload); resolve(payload); } @@ -971,7 +974,7 @@ export default class ChargingStation { this._heartbeatInterval = payload.interval * 1000; this._addConfigurationKey('HeartBeatInterval', Utils.convertToInt(payload.interval)); this._addConfigurationKey('HeartbeatInterval', Utils.convertToInt(payload.interval), false, false); - this._basicStartMessageSequence(); + this._startMessageSequence(); } else if (payload.status === 'Pending') { logger.info(this._logPrefix() + ' Charging station in pending state on the central server'); } else { @@ -1212,7 +1215,7 @@ export default class ChargingStation { // Check if authorized if (this._authorizedTags.find((value) => value === commandPayload.idTag)) { // Authorization successful start transaction - this.sendStartTransactionWithTimeout(transactionConnectorID, commandPayload.idTag); + this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID + ' for idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_ACCEPTED; } @@ -1220,7 +1223,7 @@ export default class ChargingStation { return Constants.OCPP_RESPONSE_REJECTED; } // No local authorization check required => start transaction - this.sendStartTransactionWithTimeout(transactionConnectorID, commandPayload.idTag); + this.sendStartTransaction(transactionConnectorID, commandPayload.idTag); logger.debug(this._logPrefix() + ' Transaction remotely STARTED on ' + this._stationInfo.name + '#' + transactionConnectorID + ' for idTag ' + commandPayload.idTag); return Constants.OCPP_RESPONSE_ACCEPTED; }