From 6ed92bc13120d78f84f2182ddbafd3cbcaa37359 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 12 Jun 2021 17:39:49 +0200 Subject: [PATCH] MeterValues: add Transaction.Begin and .End support MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- README.md | 7 +- .../AutomaticTransactionGenerator.ts | 4 +- src/charging-station/ChargingStation.ts | 47 ++++- .../ocpp/1.6/OCCP16IncomingRequestService.ts | 8 +- .../ocpp/1.6/OCPP16RequestService.ts | 172 +++++------------- .../ocpp/1.6/OCPP16ResponseService.ts | 6 +- .../ocpp/1.6/OCPP16ServiceUtils.ts | 62 +++++++ .../ocpp/OCPPRequestService.ts | 2 + src/types/ChargingStationTemplate.ts | 5 +- src/types/Connectors.ts | 3 +- 10 files changed, 168 insertions(+), 148 deletions(-) create mode 100644 src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts diff --git a/README.md b/README.md index a525ad66..148665b4 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ power | | | integer\|integer[] | charging stations maximum power value(s) powerSharedByConnectors | true/false | false | boolean | charging stations power shared by its connectors powerUnit | W/kW | W | string | charging stations power unit currentOutType | AC/DC | AC | string | charging stations current out type +voltageOut | | AC:230/DC:400 | integer | charging stations voltage out numberOfPhases | 0/1/3 | AC:3/DC:0 | integer | charging stations number of phase(s) numberOfConnectors | | | integer\|integer[] | charging stations number of connector(s) useConnectorId0 | true/false | true | boolean | use connector id 0 definition from the template @@ -66,8 +67,10 @@ connectionTimeout | | 30 | integer | connection timeout to the OCPP-J server autoReconnectMaxRetries | | -1 (unlimited) | integer | connection retries to the OCPP-J server reconnectExponentialDelay | true/false | false | boolean | connection delay retry to the OCPP-J server registrationMaxRetries | | -1 (unlimited) | integer | charging stations boot notification retries -enableStatistics | true/false | true | boolean | enable charging stations statistics -voltageOut | | AC:230/DC:400 | integer | charging stations voltage out +enableStatistics | true/false | true | boolean | enable charging stations statistics +beginEndMeterValues | true/false | false | boolean | enable Transaction.{Begin,End} MeterValues +outOfOrderEndMeterValues | true/false | false | boolean | send Transaction.End MeterValues out of order +meteringPerTransaction | true/false | true | boolean | disable metering on a per transaction basis Configuration | | | ChargingStationConfiguration | charging stations OCPP configuration parameters AutomaticTransactionGenerator | | | AutomaticTransactionGenerator | charging stations ATG configuration Connectors | | | Connectors | charging stations connectors configuration diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index 7268f445..942410eb 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -46,7 +46,7 @@ export default class AutomaticTransactionGenerator { const transactionId = this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionId; if (this.chargingStation.getConnector(Utils.convertToInt(connector)).transactionStarted) { logger.info(this.logPrefix(Utils.convertToInt(connector)) + ' ATG OVER. Stop transaction ' + transactionId.toString()); - await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId), + await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), this.chargingStation.getTransactionIdTag(transactionId), reason); } } @@ -149,7 +149,7 @@ export default class AutomaticTransactionGenerator { // eslint-disable-next-line consistent-this private async stopTransaction(connectorId: number, self: AutomaticTransactionGenerator): Promise { const transactionId = self.chargingStation.getConnector(connectorId).transactionId; - return await self.chargingStation.ocppRequestService.sendStopTransaction(transactionId, self.chargingStation.getTransactionMeterStop(transactionId), + return await self.chargingStation.ocppRequestService.sendStopTransaction(transactionId, self.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), self.chargingStation.getTransactionIdTag(transactionId)); } diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index e9eb86b4..50323127 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -149,14 +149,40 @@ export default class ChargingStation { } } - public getTransactionMeterStop(transactionId: number): number | undefined { + public getOutOfOrderEndMeterValues(): boolean { + return this.stationInfo.outOfOrderEndMeterValues ?? false; + } + + public getBeginEndMeterValues(): boolean { + return this.stationInfo.beginEndMeterValues ?? false; + } + + public getMeteringPerTransaction(): boolean { + return this.stationInfo.meteringPerTransaction ?? true; + } + + public getEnergyActiveImportRegisterByTransactionId(transactionId: number): number | undefined { + if (this.getMeteringPerTransaction()) { + for (const connector in this.connectors) { + if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) { + return this.getConnector(Utils.convertToInt(connector)).transactionEnergyActiveImportRegisterValue; + } + } + } for (const connector in this.connectors) { if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionId === transactionId) { - return this.getConnector(Utils.convertToInt(connector)).lastEnergyActiveImportRegisterValue; + return this.getConnector(Utils.convertToInt(connector)).energyActiveImportRegisterValue; } } } + public getEnergyActiveImportRegisterByConnectorId(connectorId: number): number | undefined { + if (this.getMeteringPerTransaction()) { + return this.getConnector(connectorId).transactionEnergyActiveImportRegisterValue; + } + return this.getConnector(connectorId).energyActiveImportRegisterValue; + } + public getAuthorizeRemoteTxRequests(): boolean { const authorizeRemoteTxRequests = this.getConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests); return authorizeRemoteTxRequests ? Utils.convertToBoolean(authorizeRemoteTxRequests.value) : false; @@ -319,7 +345,10 @@ export default class ChargingStation { } public resetTransactionOnConnector(connectorId: number): void { - this.initTransactionOnConnector(connectorId); + this.getConnector(connectorId).transactionStarted = false; + delete this.getConnector(connectorId).transactionId; + delete this.getConnector(connectorId).idTag; + this.getConnector(connectorId).transactionEnergyActiveImportRegisterValue = 0; this.stopMeterValues(connectorId); } @@ -448,7 +477,7 @@ export default class ChargingStation { // Initialize transaction attributes on connectors for (const connector in this.connectors) { if (Utils.convertToInt(connector) > 0 && !this.getConnector(Utils.convertToInt(connector)).transactionStarted) { - this.initTransactionOnConnector(Utils.convertToInt(connector)); + this.initTransactionAttributesOnConnector(Utils.convertToInt(connector)); } } switch (this.getOCPPVersion()) { @@ -756,7 +785,8 @@ export default class ChargingStation { for (const connector in this.connectors) { if (Utils.convertToInt(connector) > 0 && this.getConnector(Utils.convertToInt(connector)).transactionStarted) { const transactionId = this.getConnector(Utils.convertToInt(connector)).transactionId; - await this.ocppRequestService.sendStopTransaction(transactionId, this.getTransactionMeterStop(transactionId), this.getTransactionIdTag(transactionId), reason); + await this.ocppRequestService.sendStopTransaction(transactionId, this.getEnergyActiveImportRegisterByTransactionId(transactionId), + this.getTransactionIdTag(transactionId), reason); } } } @@ -916,11 +946,10 @@ export default class ChargingStation { } } - private initTransactionOnConnector(connectorId: number): void { + private initTransactionAttributesOnConnector(connectorId: number): void { this.getConnector(connectorId).transactionStarted = false; - delete this.getConnector(connectorId).transactionId; - delete this.getConnector(connectorId).idTag; - this.getConnector(connectorId).lastEnergyActiveImportRegisterValue = -1; + this.getConnector(connectorId).energyActiveImportRegisterValue = 0; + this.getConnector(connectorId).transactionEnergyActiveImportRegisterValue = 0; } } diff --git a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts index f230b3bc..ba1f2f7e 100644 --- a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts @@ -63,8 +63,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } if (this.chargingStation.getConnector(connectorId)?.transactionStarted) { const transactionId = this.chargingStation.getConnector(connectorId).transactionId; - const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId), - this.chargingStation.getTransactionIdTag(transactionId), OCPP16StopTransactionReason.UNLOCK_COMMAND); + const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, + this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), + this.chargingStation.getTransactionIdTag(transactionId), + OCPP16StopTransactionReason.UNLOCK_COMMAND); if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { return Constants.OCPP_RESPONSE_UNLOCKED; } @@ -297,7 +299,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer if (Utils.convertToInt(connector) > 0 && this.chargingStation.getConnector(Utils.convertToInt(connector))?.transactionId === transactionId) { await this.chargingStation.ocppRequestService.sendStatusNotification(Utils.convertToInt(connector), OCPP16ChargePointStatus.FINISHING); this.chargingStation.getConnector(Utils.convertToInt(connector)).status = OCPP16ChargePointStatus.FINISHING; - await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId), + await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), this.chargingStation.getTransactionIdTag(transactionId)); return Constants.OCPP_RESPONSE_ACCEPTED; } diff --git a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts index a5721325..4f2cac67 100644 --- a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts @@ -1,6 +1,6 @@ import { AuthorizeRequest, OCPP16AuthorizeResponse, OCPP16StartTransactionResponse, OCPP16StopTransactionReason, OCPP16StopTransactionResponse, StartTransactionRequest, StopTransactionRequest } from '../../../types/ocpp/1.6/Transaction'; import { HeartbeatRequest, OCPP16BootNotificationRequest, OCPP16IncomingRequestCommand, OCPP16RequestCommand, StatusNotificationRequest } from '../../../types/ocpp/1.6/Requests'; -import { MeterValue, MeterValueContext, MeterValueLocation, MeterValuePhase, MeterValueUnit, MeterValuesRequest, OCPP16MeterValueMeasurand, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues'; +import { MeterValue, MeterValueContext, MeterValuePhase, MeterValuesRequest, OCPP16MeterValueMeasurand, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues'; import { ACElectricUtils } from '../../../utils/ElectricUtils'; import Constants from '../../../utils/Constants'; @@ -10,6 +10,7 @@ import { MessageType } from '../../../types/ocpp/MessageType'; import { OCPP16BootNotificationResponse } from '../../../types/ocpp/1.6/Responses'; import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; +import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration'; import OCPPError from '../../OcppError'; import OCPPRequestService from '../OCPPRequestService'; @@ -75,12 +76,10 @@ export default class OCPP16RequestService extends OCPPRequestService { const payload: StartTransactionRequest = { connectorId, ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG }, - meterStart: 0, + meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId(connectorId), timestamp: new Date().toISOString(), }; - const response = await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.START_TRANSACTION) as OCPP16StartTransactionResponse; - await this.sendTransactionBeginMeterValues(connectorId, response.transactionId, 0); - return response; + return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.START_TRANSACTION) as OCPP16StartTransactionResponse; } catch (error) { this.handleRequestError(OCPP16RequestCommand.START_TRANSACTION, error); } @@ -102,7 +101,8 @@ export default class OCPP16RequestService extends OCPPRequestService { connectorId = Utils.convertToInt(connector); } } - await this.sendTransactionEndMeterValues(connectorId, transactionId, meterStop); + (this.chargingStation.getBeginEndMeterValues() && !this.chargingStation.getOutOfOrderEndMeterValues()) + && await this.sendTransactionEndMeterValues(connectorId, transactionId, meterStop); return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.STOP_TRANSACTION) as OCPP16StartTransactionResponse; } catch (error) { this.handleRequestError(OCPP16RequestCommand.STOP_TRANSACTION, error); @@ -121,27 +121,15 @@ export default class OCPP16RequestService extends OCPPRequestService { const connector = self.chargingStation.getConnector(connectorId); // SoC measurand if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.STATE_OF_CHARGE && self.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValuesSampledData).value.includes(OCPP16MeterValueMeasurand.STATE_OF_CHARGE)) { - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.PERCENT }, - ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, - measurand: meterValuesTemplate[index].measurand, - ...!Utils.isUndefined(meterValuesTemplate[index].location) ? { location: meterValuesTemplate[index].location } : { location: MeterValueLocation.EV }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: Utils.getRandomInt(100).toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], Utils.getRandomInt(100))); const sampledValuesIndex = meterValue.sampledValue.length - 1; if (Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > 100 || debug) { - logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/100`); + logger.error(`${self.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 } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.VOLTAGE && self.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValuesSampledData).value.includes(OCPP16MeterValueMeasurand.VOLTAGE)) { const voltageMeasurandValue = Utils.getRandomFloatRounded(self.chargingStation.getVoltageOut() + self.chargingStation.getVoltageOut() * 0.1, self.chargingStation.getVoltageOut() - self.chargingStation.getVoltageOut() * 0.1); - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.VOLT }, - ...!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: voltageMeasurandValue.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], voltageMeasurandValue)); for (let phase = 1; self.chargingStation.getNumberOfPhases() === 3 && phase <= self.chargingStation.getNumberOfPhases(); phase++) { let phaseValue: string; if (self.chargingStation.getVoltageOut() >= 0 && self.chargingStation.getVoltageOut() <= 250) { @@ -149,28 +137,13 @@ export default class OCPP16RequestService extends OCPPRequestService { } else if (self.chargingStation.getVoltageOut() > 250) { phaseValue = `L${phase}-L${(phase + 1) % self.chargingStation.getNumberOfPhases() !== 0 ? (phase + 1) % self.chargingStation.getNumberOfPhases() : self.chargingStation.getNumberOfPhases()}`; } - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.VOLT }, - ...!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: voltageMeasurandValue.toString() }, - phase: phaseValue as MeterValuePhase, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], voltageMeasurandValue, null, + phaseValue as MeterValuePhase)); } // Power.Active.Import measurand } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT && self.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValuesSampledData).value.includes(OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT)) { - // FIXME: factor out powerDivider checks - if (Utils.isUndefined(self.chargingStation.stationInfo.powerDivider)) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`; - logger.error(errMsg); - throw Error(errMsg); - } else if (self.chargingStation.stationInfo.powerDivider && self.chargingStation.stationInfo.powerDivider <= 0) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`; - logger.error(errMsg); - throw Error(errMsg); - } - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`; + OCPP16ServiceUtils.checkMeasurandPowerDivider(self.chargingStation, meterValuesTemplate[index].measurand); + const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`; const powerMeasurandValues = {} as MeasurandValues; const maxPower = Math.round(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider); const maxPowerPerPhase = Math.round((self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider) / self.chargingStation.getNumberOfPhases()); @@ -196,41 +169,20 @@ export default class OCPP16RequestService extends OCPPRequestService { logger.error(errMsg); throw Error(errMsg); } - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.WATT }, - ...!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: powerMeasurandValues.allPhases.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], powerMeasurandValues.allPhases)); const sampledValuesIndex = meterValue.sampledValue.length - 1; if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPower || debug) { - logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPower}`); + logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPower}`); } for (let phase = 1; self.chargingStation.getNumberOfPhases() === 3 && phase <= self.chargingStation.getNumberOfPhases(); phase++) { const phaseValue = `L${phase}-N`; - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.WATT }, - ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, - ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, - ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: powerMeasurandValues[`L${phase}`] as string }, - phase: phaseValue as MeterValuePhase, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], powerMeasurandValues[`L${phase}`], null, + phaseValue as MeterValuePhase)); } // Current.Import measurand } else if (meterValuesTemplate[index].measurand && meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.CURRENT_IMPORT && self.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValuesSampledData).value.includes(OCPP16MeterValueMeasurand.CURRENT_IMPORT)) { - // FIXME: factor out powerDivider checks - if (Utils.isUndefined(self.chargingStation.stationInfo.powerDivider)) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`; - logger.error(errMsg); - throw Error(errMsg); - } else if (self.chargingStation.stationInfo.powerDivider && self.chargingStation.stationInfo.powerDivider <= 0) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`; - logger.error(errMsg); - throw Error(errMsg); - } - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`; + OCPP16ServiceUtils.checkMeasurandPowerDivider(self.chargingStation, meterValuesTemplate[index].measurand); + const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`; const currentMeasurandValues: MeasurandValues = {} as MeasurandValues; let maxAmperage: number; switch (self.chargingStation.getCurrentOutType()) { @@ -257,65 +209,41 @@ export default class OCPP16RequestService extends OCPPRequestService { logger.error(errMsg); throw Error(errMsg); } - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.AMP }, - ...!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: currentMeasurandValues.allPhases.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], currentMeasurandValues.allPhases)); const sampledValuesIndex = meterValue.sampledValue.length - 1; if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxAmperage || debug) { - logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxAmperage}`); + logger.error(`${self.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; self.chargingStation.getNumberOfPhases() === 3 && phase <= self.chargingStation.getNumberOfPhases(); phase++) { const phaseValue = `L${phase}`; - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.AMP }, - ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, - ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, - ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : { value: currentMeasurandValues[phaseValue] as string }, - phase: phaseValue as MeterValuePhase, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], currentMeasurandValues[phaseValue], null, + phaseValue as MeterValuePhase)); } // Energy.Active.Import.Register measurand (default) } else if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - // FIXME: factor out powerDivider checks - if (Utils.isUndefined(self.chargingStation.stationInfo.powerDivider)) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`; - logger.error(errMsg); - throw Error(errMsg); - } else if (self.chargingStation.stationInfo.powerDivider && self.chargingStation.stationInfo.powerDivider <= 0) { - const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`; - logger.error(errMsg); - throw Error(errMsg); - } + OCPP16ServiceUtils.checkMeasurandPowerDivider(self.chargingStation, meterValuesTemplate[index].measurand); if (Utils.isUndefined(meterValuesTemplate[index].value)) { const measurandValue = Utils.getRandomInt(self.chargingStation.stationInfo.maxPower / (self.chargingStation.stationInfo.powerDivider * 3600000) * interval); // Persist previous value in connector - if (connector && !Utils.isNullOrUndefined(connector.lastEnergyActiveImportRegisterValue) && connector.lastEnergyActiveImportRegisterValue >= 0) { - connector.lastEnergyActiveImportRegisterValue += measurandValue; + if (connector && !Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) && connector.energyActiveImportRegisterValue >= 0 && + !Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) && connector.transactionEnergyActiveImportRegisterValue >= 0) { + connector.energyActiveImportRegisterValue += measurandValue; + connector.transactionEnergyActiveImportRegisterValue += measurandValue; } else { - connector.lastEnergyActiveImportRegisterValue = 0; + connector.energyActiveImportRegisterValue = 0; + connector.transactionEnergyActiveImportRegisterValue = 0; } } - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.WATT_HOUR }, - ...!Utils.isUndefined(meterValuesTemplate[index].context) && { context: meterValuesTemplate[index].context }, - ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, - ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : - { value: connector.lastEnergyActiveImportRegisterValue.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], + self.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId))); const sampledValuesIndex = meterValue.sampledValue.length - 1; const maxConsumption = Math.round(self.chargingStation.stationInfo.maxPower * 3600 / (self.chargingStation.stationInfo.powerDivider * interval)); if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxConsumption || debug) { - logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxConsumption}`); + logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxConsumption}`); } // Unsupported measurand } else { - logger.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`); + logger.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`); } } const payload: MeterValuesRequest = { @@ -329,12 +257,7 @@ export default class OCPP16RequestService extends OCPPRequestService { } } - public async sendError(messageId: string, error: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { - // Send error - return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); - } - - private async sendTransactionBeginMeterValues(connectorId: number, transactionId: number, meterBegin: number) { + public async sendTransactionBeginMeterValues(connectorId: number, transactionId: number, meterBegin: number): Promise { const meterValue: MeterValue = { timestamp: new Date().toISOString(), sampledValue: [], @@ -343,14 +266,7 @@ export default class OCPP16RequestService extends OCPPRequestService { for (let index = 0; index < meterValuesTemplate.length; index++) { // Energy.Active.Import.Register measurand (default) if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.WATT_HOUR }, - context: MeterValueContext.TRANSACTION_BEGIN, - ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, - ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : - { value: meterBegin.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], meterBegin, MeterValueContext.TRANSACTION_BEGIN)); } } const payload: MeterValuesRequest = { @@ -361,7 +277,7 @@ export default class OCPP16RequestService extends OCPPRequestService { await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METER_VALUES); } - private async sendTransactionEndMeterValues(connectorId: number, transactionId: number, meterEnd: number) { + public async sendTransactionEndMeterValues(connectorId: number, transactionId: number, meterEnd: number): Promise { const meterValue: MeterValue = { timestamp: new Date().toISOString(), sampledValue: [], @@ -370,14 +286,7 @@ export default class OCPP16RequestService extends OCPPRequestService { for (let index = 0; index < meterValuesTemplate.length; index++) { // Energy.Active.Import.Register measurand (default) if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { - meterValue.sampledValue.push({ - ...!Utils.isUndefined(meterValuesTemplate[index].unit) ? { unit: meterValuesTemplate[index].unit } : { unit: MeterValueUnit.WATT_HOUR }, - context: MeterValueContext.TRANSACTION_END, - ...!Utils.isUndefined(meterValuesTemplate[index].measurand) && { measurand: meterValuesTemplate[index].measurand }, - ...!Utils.isUndefined(meterValuesTemplate[index].location) && { location: meterValuesTemplate[index].location }, - ...!Utils.isUndefined(meterValuesTemplate[index].value) ? { value: meterValuesTemplate[index].value } : - { value: meterEnd.toString() }, - }); + meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], meterEnd, MeterValueContext.TRANSACTION_END)); } } const payload: MeterValuesRequest = { @@ -387,4 +296,9 @@ export default class OCPP16RequestService extends OCPPRequestService { }; await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METER_VALUES); } + + public async sendError(messageId: string, error: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { + // Send error + return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); + } } diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index e9d2d2e9..0f12f2f2 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -54,7 +54,9 @@ export default class OCPP16ResponseService extends OCPPResponseService { this.chargingStation.getConnector(connectorId).transactionStarted = true; this.chargingStation.getConnector(connectorId).transactionId = payload.transactionId; this.chargingStation.getConnector(connectorId).idTag = requestPayload.idTag; - this.chargingStation.getConnector(connectorId).lastEnergyActiveImportRegisterValue = 0; + this.chargingStation.getConnector(connectorId).transactionEnergyActiveImportRegisterValue = 0; + this.chargingStation.getBeginEndMeterValues() && await this.chargingStation.ocppRequestService.sendTransactionBeginMeterValues(connectorId, payload.transactionId, + this.chargingStation.getEnergyActiveImportRegisterByTransactionId(payload.transactionId)); await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.CHARGING); this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.CHARGING; logger.info(this.chargingStation.logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag); @@ -84,6 +86,8 @@ export default class OCPP16ResponseService extends OCPPResponseService { return; } if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { + (this.chargingStation.getBeginEndMeterValues() && this.chargingStation.getOutOfOrderEndMeterValues()) + && await this.chargingStation.ocppRequestService.sendTransactionEndMeterValues(transactionConnectorId, requestPayload.transactionId, requestPayload.meterStop); if (!this.chargingStation.isChargingStationAvailable() || !this.chargingStation.isConnectorAvailable(transactionConnectorId)) { await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.UNAVAILABLE); this.chargingStation.getConnector(transactionConnectorId).status = OCPP16ChargePointStatus.UNAVAILABLE; diff --git a/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts new file mode 100644 index 00000000..5a2bfa9c --- /dev/null +++ b/src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts @@ -0,0 +1,62 @@ +import { MeterValueContext, MeterValueLocation, MeterValuePhase, MeterValueUnit, OCPP16MeterValueMeasurand, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues'; + +import ChargingStation from '../../ChargingStation'; +import Utils from '../../../utils/Utils'; +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`; + logger.error(errMsg); + throw Error(errMsg); + } else if (chargingStation.stationInfo.powerDivider && 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}`; + logger.error(errMsg); + throw Error(errMsg); + } + } + + public static buildSampledValue(sampledValueTemplate: OCPP16SampledValue, value: number, context?: MeterValueContext, phase?: MeterValuePhase): OCPP16SampledValue { + const sampledValueContext = context ?? (sampledValueTemplate.context ?? null); + const sampledValueLocation = sampledValueTemplate.location + ? sampledValueTemplate.location + : (OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate.measurand ?? null)); + const sampledValuePhase = phase ?? (sampledValueTemplate.phase ?? null); + return { + ...!Utils.isNullOrUndefined(sampledValueTemplate.unit) && { unit: sampledValueTemplate.unit }, + ...!Utils.isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }, + ...!Utils.isNullOrUndefined(sampledValueTemplate.measurand) && { measurand: sampledValueTemplate.measurand }, + ...!Utils.isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }, + ...!Utils.isNullOrUndefined(sampledValueTemplate.value) ? { value: sampledValueTemplate.value } : { value: value.toString() }, + ...!Utils.isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }, + }; + } + + public static getMeasurandDefaultUnit(measurandType: OCPP16MeterValueMeasurand): MeterValueUnit { + switch (measurandType) { + case OCPP16MeterValueMeasurand.CURRENT_EXPORT: + case OCPP16MeterValueMeasurand.CURRENT_IMPORT: + case OCPP16MeterValueMeasurand.CURRENT_OFFERED: + return MeterValueUnit.AMP; + case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER: + case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER: + return MeterValueUnit.WATT_HOUR; + case OCPP16MeterValueMeasurand.POWER_ACTIVE_EXPORT: + case OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT: + case OCPP16MeterValueMeasurand.POWER_OFFERED: + return MeterValueUnit.WATT; + case OCPP16MeterValueMeasurand.STATE_OF_CHARGE: + return MeterValueUnit.PERCENT; + case OCPP16MeterValueMeasurand.VOLTAGE: + return MeterValueUnit.VOLT; + } + } + + public static getMeasurandDefaultLocation(measurandType: OCPP16MeterValueMeasurand): MeterValueLocation { + switch (measurandType) { + case OCPP16MeterValueMeasurand.STATE_OF_CHARGE: + return MeterValueLocation.EV; + } + } +} diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 70742ea8..17acfbf9 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -114,5 +114,7 @@ export default abstract class OCPPRequestService { public abstract sendStartTransaction(connectorId: number, idTag?: string): Promise; public abstract sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason?: StopTransactionReason): Promise; public abstract sendMeterValues(connectorId: number, transactionId: number, interval: number, self: OCPPRequestService): Promise; + public abstract sendTransactionBeginMeterValues(connectorId: number, transactionId: number, meterBegin: number): Promise; + public abstract sendTransactionEndMeterValues(connectorId: number, transactionId: number, meterEnd: number): Promise; public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise; } diff --git a/src/types/ChargingStationTemplate.ts b/src/types/ChargingStationTemplate.ts index dbe9b8d2..13d8e75b 100644 --- a/src/types/ChargingStationTemplate.ts +++ b/src/types/ChargingStationTemplate.ts @@ -47,6 +47,7 @@ export default interface ChargingStationTemplate { powerSharedByConnectors?: boolean; powerUnit: PowerUnits; currentOutType?: CurrentOutType; + voltageOut?: number; numberOfPhases?: number; numberOfConnectors?: number | number[]; useConnectorId0?: boolean; @@ -57,7 +58,9 @@ export default interface ChargingStationTemplate { reconnectExponentialDelay?: boolean; registrationMaxRetries?: number; enableStatistics?: boolean; - voltageOut?: number; + beginEndMeterValues?: boolean; + outOfOrderEndMeterValues?: boolean; + meteringPerTransaction?: boolean; Configuration?: ChargingStationConfiguration; AutomaticTransactionGenerator: AutomaticTransactionGenerator; Connectors: Connectors; diff --git a/src/types/Connectors.ts b/src/types/Connectors.ts index 38bebf33..0a2a6f39 100644 --- a/src/types/Connectors.ts +++ b/src/types/Connectors.ts @@ -12,7 +12,8 @@ export interface Connector { transactionId?: number; transactionSetInterval?: NodeJS.Timeout; idTag?: string; - lastEnergyActiveImportRegisterValue?: number; + energyActiveImportRegisterValue?: number; + transactionEnergyActiveImportRegisterValue?: number; chargingProfiles?: ChargingProfile[] } -- 2.34.1