+ async sendStartTransaction(connectorID, idTag) {
+ try {
+ const payload = {
+ connectorId: connectorID,
+ idTag,
+ meterStart: 0,
+ timestamp: new Date().toISOString(),
+ };
+ return await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StartTransaction');
+ } catch (error) {
+ logger.error(this._basicFormatLog() + ' Send StartTransaction error: ' + error);
+ throw error;
+ }
+ }
+
+ sendStartTransactionWithTimeout(connectorID, idTag, timeout) {
+ setTimeout(() => this.sendStartTransaction(connectorID, idTag), timeout);
+ }
+
+ async sendStopTransaction(transactionId, reason = '') {
+ try {
+ let payload = {};
+ if (reason) {
+ payload = {
+ transactionId,
+ meterStop: 0,
+ timestamp: new Date().toISOString(),
+ reason,
+ };
+ } else {
+ payload = {
+ transactionId,
+ meterStop: 0,
+ timestamp: new Date().toISOString(),
+ };
+ }
+ await this.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'StopTransaction');
+ } catch (error) {
+ logger.error(this._basicFormatLog() + ' Send StopTransaction error: ' + error);
+ throw error;
+ }
+ }
+
+ // eslint-disable-next-line class-methods-use-this
+ async sendMeterValues(connectorID, interval, self, debug = false) {
+ try {
+ const sampledValueLcl = {
+ timestamp: new Date().toISOString(),
+ };
+ const meterValuesClone = Utils.cloneJSonDocument(self._getConnector(connectorID).MeterValues);
+ if (!Utils.isEmptyArray(meterValuesClone)) {
+ sampledValueLcl.sampledValue = meterValuesClone;
+ } else {
+ sampledValueLcl.sampledValue = [meterValuesClone];
+ }
+ for (let index = 0; index < sampledValueLcl.sampledValue.length; index++) {
+ const connector = self._connectors[connectorID];
+ // SoC measurand
+ if (sampledValueLcl.sampledValue[index].measurand && sampledValueLcl.sampledValue[index].measurand === 'SoC') {
+ sampledValueLcl.sampledValue[index].value = sampledValueLcl.sampledValue[index].value ?
+ sampledValueLcl.sampledValue[index].value :
+ sampledValueLcl.sampledValue[index].value = Utils.getRandomInt(100);
+ if (sampledValueLcl.sampledValue[index].value > 100 || debug) {
+ logger.error(`${self._basicFormatLog()} MeterValues measurand ${sampledValueLcl.sampledValue[index].measurand ? sampledValueLcl.sampledValue[index].measurand : 'Energy.Active.Import.Register'}: connectorID ${connectorID}, transaction ${connector.transactionId}, value: ${sampledValueLcl.sampledValue[index].value}`);
+ }
+ // Voltage measurand
+ } else if (sampledValueLcl.sampledValue[index].measurand && sampledValueLcl.sampledValue[index].measurand === 'Voltage') {
+ sampledValueLcl.sampledValue[index].value = sampledValueLcl.sampledValue[index].value ? sampledValueLcl.sampledValue[index].value : 230;
+ // Energy.Active.Import.Register measurand (default)
+ } else if (!sampledValueLcl.sampledValue[index].measurand || sampledValueLcl.sampledValue[index].measurand === 'Energy.Active.Import.Register') {
+ if (!sampledValueLcl.sampledValue[index].value) {
+ const measurandValue = Utils.getRandomInt(self._stationInfo.maxPower / 3600000 * interval);
+ // Persist previous value in connector
+ if (connector && connector.lastEnergyActiveImportRegisterValue >= 0) {
+ connector.lastEnergyActiveImportRegisterValue += measurandValue;
+ } else {
+ connector.lastEnergyActiveImportRegisterValue = 0;
+ }
+ sampledValueLcl.sampledValue[index].value = connector.lastEnergyActiveImportRegisterValue;
+ }
+ logger.info(`${self._basicFormatLog()} MeterValues measurand ${sampledValueLcl.sampledValue[index].measurand ? sampledValueLcl.sampledValue[index].measurand : 'Energy.Active.Import.Register'}: connectorID ${connectorID}, transaction ${connector.transactionId}, value ${sampledValueLcl.sampledValue[index].value}`);
+ const maxConsumption = self._stationInfo.maxPower * 3600 / interval;
+ if (sampledValueLcl.sampledValue[index].value > maxConsumption || debug) {
+ logger.error(`${self._basicFormatLog()} MeterValues measurand ${sampledValueLcl.sampledValue[index].measurand ? sampledValueLcl.sampledValue[index].measurand : 'Energy.Active.Import.Register'}: connectorID ${connectorID}, transaction ${connector.transactionId}, value: ${sampledValueLcl.sampledValue[index].value}/${maxConsumption}`);
+ }
+ // Unsupported measurand
+ } else {
+ logger.info(`${self._basicFormatLog()} Unsupported MeterValues measurand ${sampledValueLcl.sampledValue[index].measurand ? sampledValueLcl.sampledValue[index].measurand : 'Energy.Active.Import.Register'} on connectorID ${connectorID}`);
+ }
+ }
+
+ const payload = {
+ connectorId: connectorID,
+ transactionId: self._connectors[connectorID].transactionId,
+ meterValue: [sampledValueLcl],
+ };
+ await self.sendMessage(Utils.generateUUID(), payload, Constants.OCPP_JSON_CALL_MESSAGE, 'MeterValues');
+ } catch (error) {
+ logger.error(self._basicFormatLog() + ' Send MeterValues error: ' + error);
+ throw error;
+ }
+ }
+
+ sendError(messageId, err) {
+ // Check exception: only OCPP error are accepted
+ const error = err instanceof OCPPError ? err : new OCPPError(Constants.OCPP_ERROR_INTERNAL_ERROR, err.message);
+ // Send error
+ return this.sendMessage(messageId, error, Constants.OCPP_JSON_CALL_ERROR_MESSAGE);
+ }
+