Fixed OCPP wrong typing + Typed TransactionData + Enhanced logs + use Constants
MODIFY
src/client/ocpp/soap/SoapChargingStationClient.ts
src/client/ocpp/soap/SoapChargingStationClient.ts
@@ -4,6 +4,7 @@ import { OCPPChangeAvailabilityCommandParam, OCPPChangeAvailabilityCommandResult
import ChargingStationClient from '../ChargingStationClient';
import Configuration from '../../../utils/Configuration';
import Logging from '../../../utils/Logging';
+import { OCPPVersion } from '../../../types/ocpp/OCPPServer';
import { ServerAction } from '../../../types/Server';
import global from '../../../types/GlobalType';
import { soap } from 'strong-soap';
@@ -37,18 +38,19 @@ export default class SoapChargingStationClient extends ChargingStationClient {
static async getChargingStationClient(tenantID: string, chargingStation: ChargingStation): Promise<SoapChargingStationClient> {
const scsc = new SoapChargingStationClient(tenantID, chargingStation);
+ // eslint-disable-next-line no-undef
return await new Promise((fulfill, reject) => {
let chargingStationWdsl = null;
// Read the WSDL client files
switch (scsc.chargingStation.ocppVersion) {
// OCPP V1.2
- case '1.2':
+ case OCPPVersion.VERSION_12:
chargingStationWdsl = `${global.appRoot}/assets/server/ocpp/wsdl/OCPPChargePointService12.wsdl`;
break;
- case '1.5':
+ case OCPPVersion.VERSION_15:
chargingStationWdsl = `${global.appRoot}/assets/server/ocpp/wsdl/OCPPChargePointService15.wsdl`;
break;
- case '1.6':
+ case OCPPVersion.VERSION_16:
chargingStationWdsl = `${global.appRoot}/assets/server/ocpp/wsdl/OCPPChargePointService16.wsdl`;
break;
default:

MODIFY
src/server/ocpp/json/JsonWSConnection.ts
src/server/ocpp/json/JsonWSConnection.ts
@@ -121,7 +121,7 @@ export default class JsonWSConnection extends WSConnection {
module: MODULE_NAME,
method: 'handleRequest',
code: OcppErrorType.NOT_IMPLEMENTED,
- message: `The OCPP method 'handle${commandName}' has not been implemented`
+ message: `The OCPP method 'handle${typeof commandName === 'string' ? commandName : JSON.stringify(commandName)}' has not been implemented`
});
}
}

MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
-import { ChargePointStatus, OCPPAttribute, OCPPAuthorizationStatus, OCPPAuthorizeRequestExtended, OCPPAuthorizeResponse, OCPPBootNotificationRequestExtended, OCPPBootNotificationResponse, OCPPDataTransferRequestExtended, OCPPDataTransferResponse, OCPPDataTransferStatus, OCPPDiagnosticsStatusNotificationRequestExtended, OCPPDiagnosticsStatusNotificationResponse, OCPPFirmwareStatusNotificationRequestExtended, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatRequestExtended, OCPPHeartbeatResponse, OCPPLocation, OCPPMeasurand, OCPPMeterValuesExtended, OCPPMeterValuesResponse, OCPPNormalizedMeterValue, OCPPNormalizedMeterValues, OCPPReadingContext, OCPPSampledValue, OCPPStartTransactionRequestExtended, OCPPStartTransactionResponse, OCPPStatusNotificationRequestExtended, OCPPStatusNotificationResponse, OCPPStopTransactionRequestExtended, OCPPStopTransactionResponse, OCPPUnitOfMeasure, OCPPValueFormat, OCPPVersion, RegistrationStatus } from '../../../types/ocpp/OCPPServer';
+import { ChargePointStatus, OCPPAttribute, OCPPAuthorizationStatus, OCPPAuthorizeRequestExtended, OCPPAuthorizeResponse, OCPPBootNotificationRequestExtended, OCPPBootNotificationResponse, OCPPDataTransferRequestExtended, OCPPDataTransferResponse, OCPPDataTransferStatus, OCPPDiagnosticsStatusNotificationRequestExtended, OCPPDiagnosticsStatusNotificationResponse, OCPPFirmwareStatusNotificationRequestExtended, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatRequestExtended, OCPPHeartbeatResponse, OCPPIdTagInfo, OCPPLocation, OCPPMeasurand, OCPPMeterValuesExtended, OCPPMeterValuesResponse, OCPPNormalizedMeterValue, OCPPNormalizedMeterValues, OCPPReadingContext, OCPPSampledValue, OCPPStartTransactionRequestExtended, OCPPStartTransactionResponse, OCPPStatusNotificationRequestExtended, OCPPStatusNotificationResponse, OCPPStopTransactionRequestExtended, OCPPStopTransactionResponse, OCPPUnitOfMeasure, OCPPValueFormat, OCPPVersion, RegistrationStatus } from '../../../types/ocpp/OCPPServer';
import { ChargingProfilePurposeType, ChargingRateUnitType } from '../../../types/ChargingProfile';
import ChargingStation, { ChargerVendor, Connector, ConnectorCurrentLimitSource, ConnectorType, SiteAreaLimitSource } from '../../../types/ChargingStation';
import Transaction, { InactivityStatus, TransactionAction } from '../../../types/Transaction';
@@ -199,7 +199,7 @@ export default class OCPPService {
message: 'Boot notification saved'
});
// Handle the get of configuration later on
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-undef
setTimeout(async () => {
// Get config and save it
await OCPPUtils.requestAndSaveChargingStationOcppParameters(
@@ -434,6 +434,9 @@ export default class OCPPService {
chargingStation, transaction.connectorId, transaction.currentTotalInactivitySecs);
// Instant Power not present in Meter Value
if (!consumption.instantWatts) {
+ // Console.log('====================================');
+ // console.log('Build Watt');
+ // console.log('====================================');
// Compute average Instant Power based on consumption over a time period (usually 60s)
const diffSecs = moment(consumption.endedAt).diff(consumption.startedAt, 'milliseconds') / 1000;
if (consumption.consumptionWh > 0) {
@@ -447,7 +450,7 @@ export default class OCPPService {
}
}
- public async handleAuthorize(headers: OCPPHeader, authorize: OCPPAuthorizeRequestExtended): Promise<OCPPAuthorizeResponse> {
+ public async handleAuthorize(headers: OCPPHeader, authorize: OCPPAuthorizeRequestExtended): Promise<OCPPIdTagInfo> {
try {
// Get the charging station
const chargingStation = await OCPPUtils.checkAndGetChargingStation(headers.chargeBoxIdentity, headers.tenantID);
@@ -759,7 +762,7 @@ export default class OCPPService {
}
}
- public async handleStopTransaction(headers: OCPPHeader, stopTransaction: OCPPStopTransactionRequestExtended, isSoftStop = false, stoppedByCentralSystem = false): Promise<OCPPStopTransactionResponse> {
+ public async handleStopTransaction(headers: OCPPHeader, stopTransaction: OCPPStopTransactionRequestExtended, isSoftStop = false, stoppedByCentralSystem = false): Promise<OCPPIdTagInfo> {
try {
// Get the charging station
const chargingStation = await OCPPUtils.checkAndGetChargingStation(headers.chargeBoxIdentity, headers.tenantID);
@@ -862,7 +865,7 @@ export default class OCPPService {
// Delete TxProfile if any
await this.deleteAllTransactionTxProfile(headers.tenantID, transaction);
// Call async because the Transaction ID on the connector should be cleared
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-undef
setTimeout(async () => {
try {
// Trigger Smart Charging
@@ -1795,7 +1798,7 @@ export default class OCPPService {
'timestamp': Utils.convertToDate(activeTransaction.lastEnergyActiveImportMeterValue ? activeTransaction.lastEnergyActiveImportMeterValue.timestamp : activeTransaction.timestamp).toISOString(),
}, false, true);
// Check
- if (result.status === 'Invalid') {
+ if (result.status === OCPPAuthorizationStatus.INVALID) {
// No consumption: delete
Logging.logError({
tenantID: tenantID,

MODIFY
src/server/ocpp/soap/SoapCentralSystemServer.ts
src/server/ocpp/soap/SoapCentralSystemServer.ts
@@ -3,6 +3,7 @@ import CentralSystemServer from '../CentralSystemServer';
import ChargingStationConfiguration from '../../../types/configuration/ChargingStationConfiguration';
import Constants from '../../../utils/Constants';
import Logging from '../../../utils/Logging';
+import { OCPPVersion } from '../../../types/ocpp/OCPPServer';
import { ServerAction } from '../../../types/Server';
import centralSystemService12 from './services/SoapCentralSystemService12';
import centralSystemService15 from './services/SoapCentralSystemService15';
@@ -87,11 +88,11 @@ export default class SoapCentralSystemServer extends CentralSystemServer {
if (this.centralSystemConfig.debug) {
// Listen
soapServer15.log = (type, data) => {
- this.handleSoapServerLog('1.5', type, data);
+ this.handleSoapServerLog(OCPPVersion.VERSION_15, type, data);
};
// Log Request
soapServer15.on('request', (request, methodName) => {
- this.handleSoapServerMessage('1.5', request, methodName);
+ this.handleSoapServerMessage(OCPPVersion.VERSION_15, request, methodName);
});
}
// OCPP 1.6 -----------------------------------------
@@ -100,11 +101,11 @@ export default class SoapCentralSystemServer extends CentralSystemServer {
if (this.centralSystemConfig.debug) {
// Listen
soapServer16.log = (type, data) => {
- this.handleSoapServerLog('1.6', type, data);
+ this.handleSoapServerLog(OCPPVersion.VERSION_16, type, data);
};
// Log Request
soapServer16.on('request', (request, methodName) => {
- this.handleSoapServerMessage('1.6', request, methodName);
+ this.handleSoapServerMessage(OCPPVersion.VERSION_16, request, methodName);
});
}
}

MODIFY
src/server/rest/service/TransactionService.ts
src/server/rest/service/TransactionService.ts
@@ -6,7 +6,6 @@ import { ActionsResponse } from '../../../types/GlobalType';
import AppAuthError from '../../../exception/AppAuthError';
import AppError from '../../../exception/AppError';
import Authorizations from '../../../authorization/Authorizations';
-import ChargingStation from '../../../types/ChargingStation';
import ChargingStationStorage from '../../../storage/mongodb/ChargingStationStorage';
import Configuration from '../../../utils/Configuration';
import Constants from '../../../utils/Constants';

MODIFY
src/server/rest/validation/SchemaValidator.ts
src/server/rest/validation/SchemaValidator.ts
@@ -33,14 +33,21 @@ export default class SchemaValidator {
path: error.dataPath,
message: error.message ? error.message : ''
}));
- const concatenatedError = { path: errors.map((e) => e.path).join(','), message: errors.map((e) => e.message).join(',') };
+ const concatenatedErrors: string[] = [];
+ for (const error of errors) {
+ if (error.path && error.path !== '') {
+ concatenatedErrors.push(`Property '${error.path}': ${error.message}`);
+ } else {
+ concatenatedErrors.push(`Error: ${error.message}`);
+ }
+ }
throw new AppError({
source: Constants.CENTRAL_SERVER,
errorCode: HTTPError.GENERAL_ERROR,
- message: concatenatedError.message,
+ message: concatenatedErrors.join(', '),
module: this.moduleName,
method: 'validate',
- detailedMessages: { concatenatedError }
+ detailedMessages: { errors, content, schema }
});
}
}

MODIFY
src/types/ocpp/OCPPServer.ts
src/types/ocpp/OCPPServer.ts
@@ -90,15 +90,15 @@ export interface OCPPMeterValuesRequest {
export interface OCPP15MeterValuesRequest {
connectorId: number;
transactionId?: number;
- values: OCPP15MeterValues|OCPP15MeterValues[];
+ values: OCPP15MeterValue|OCPP15MeterValue[];
}
-export interface OCPP15MeterValues {
+export interface OCPP15MeterValue {
timestamp: string;
- value: OCPP15MeterValue|OCPP15MeterValue[];
+ value: OCPP15MeterValueValue|OCPP15MeterValueValue[];
}
-export interface OCPP15MeterValue {
+export interface OCPP15MeterValueValue {
$attributes: OCPPAttribute;
$value: string;
}
@@ -390,7 +390,11 @@ export interface OCPPStopTransactionRequest {
timestamp: string;
transactionId: number;
reason?: OCPPReason;
- transactionData?: OCPPMeterValue[];
+ transactionData?: OCPP15TransactionData|OCPPMeterValue[];
+}
+
+export interface OCPP15TransactionData {
+ values: OCPP15MeterValue|OCPP15MeterValue[];
}
export enum OCPPReason {

MODIFY
test/api/OCPPCommonTests.ts
test/api/OCPPCommonTests.ts
-import { ChargePointErrorCode, ChargePointStatus, OCPPStatusNotificationRequest } from '../../src/types/ocpp/OCPPServer';
+import { ChargePointErrorCode, ChargePointStatus, OCPP15TransactionData, OCPPLocation, OCPPMeasurand, OCPPMeterValue, OCPPReadingContext, OCPPStatusNotificationRequest, OCPPUnitOfMeasure, OCPPValueFormat, OCPPVersion } from '../../src/types/ocpp/OCPPServer';
import Transaction, { InactivityStatus } from '../../src/types/Transaction';
import chai, { expect } from 'chai';
@@ -567,6 +567,8 @@ export default class OCPPCommonTests {
// Transaction must be deleted by Admin user
response = await this.centralUserService.transactionApi.delete(this.newTransaction.id);
}
+ // Remove from transactions to be deleted
+ this.chargingStationContext.removeTransaction(this.newTransaction.id);
expect(response.status).to.equal(200);
expect(response.data).to.have.property('status');
expect(response.data.status).to.be.eql('Success');
@@ -710,19 +712,19 @@ export default class OCPPCommonTests {
const transactionId = startTransactionResponse.transactionId;
this.transactionCurrentTime = moment().toDate();
const stopValue = this.transactionStartMeterValue + faker.random.number(100000);
- let transactionData;
- if (this.chargingStationContext.getChargingStation().ocppVersion === '1.6') {
+ let transactionData: OCPPMeterValue[] | OCPP15TransactionData;
+ if (this.chargingStationContext.getChargingStation().ocppVersion === OCPPVersion.VERSION_16) {
transactionData = [
{
'timestamp': this.transactionStartTime.toISOString(),
'sampledValue': [
{
- 'value': this.transactionStartMeterValue,
- 'context': 'Transaction.Begin',
- 'format': 'Raw',
- 'measurand': 'Energy.Active.Import.Register',
- 'location': 'Outlet',
- 'unit': 'Wh'
+ 'value': this.transactionStartMeterValue.toString(),
+ 'context': OCPPReadingContext.TRANSACTION_BEGIN,
+ 'format': OCPPValueFormat.RAW,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'location': OCPPLocation.OUTLET,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
}
]
},
@@ -730,43 +732,44 @@ export default class OCPPCommonTests {
'timestamp': this.transactionCurrentTime.toISOString(),
'sampledValue': [
{
- 'value': stopValue,
- 'context': 'Transaction.End',
- 'format': 'Raw',
- 'measurand': 'Energy.Active.Import.Register',
- 'location': 'Outlet',
- 'unit': 'Wh'
+ 'value': stopValue.toString(),
+ 'context': OCPPReadingContext.TRANSACTION_END,
+ 'format': OCPPValueFormat.RAW,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'location': OCPPLocation.OUTLET,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
}
]
}
];
+ // OCPP 1.5
} else {
transactionData = {
'values': [
{
'timestamp': this.transactionStartTime.toISOString(),
'value': {
- 'attributes': {
- 'context': 'Transaction.Begin',
- 'format': 'Raw',
- 'location': 'Outlet',
- 'measurand': 'Energy.Active.Import.Register',
- 'unit': 'Wh'
+ '$attributes': {
+ 'context': OCPPReadingContext.TRANSACTION_BEGIN,
+ 'format': OCPPValueFormat.RAW,
+ 'location': OCPPLocation.OUTLET,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
},
- '$value': this.transactionStartMeterValue,
+ '$value': this.transactionStartMeterValue.toString(),
}
},
{
'timestamp': this.transactionCurrentTime.toISOString(),
'value': {
- 'attributes': {
- 'context': 'Transaction.End',
- 'format': 'Raw',
- 'location': 'Outlet',
- 'measurand': 'Energy.Active.Import.Register',
- 'unit': 'Wh'
+ '$attributes': {
+ 'context': OCPPReadingContext.TRANSACTION_END,
+ 'format': OCPPValueFormat.RAW,
+ 'location': OCPPLocation.OUTLET,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
},
- '$value': stopValue
+ '$value': stopValue.toString()
}
}
]
@@ -789,20 +792,20 @@ export default class OCPPCommonTests {
const transactionId = startTransactionResponse.transactionId;
this.transactionCurrentTime = moment().toDate();
const stopValue = this.transactionStartMeterValue + faker.random.number(100000);
- let transactionData;
+ let transactionData: OCPPMeterValue[] | OCPP15TransactionData;
// Provide TransactionData for wrong OCPP Version
- if (this.chargingStationContext.getChargingStation().ocppVersion === '1.5') {
+ if (this.chargingStationContext.getChargingStation().ocppVersion === OCPPVersion.VERSION_15) {
transactionData = [
{
'timestamp': this.transactionStartTime.toISOString(),
'sampledValue': [
{
- 'value': this.transactionStartMeterValue,
- 'context': 'Transaction.Begin',
- 'format': 'Raw',
- 'measurand': 'Energy.Active.Import.Register',
- 'location': 'Outlet',
- 'unit': 'Wh'
+ 'value': this.transactionStartMeterValue.toString(),
+ 'context': OCPPReadingContext.TRANSACTION_BEGIN,
+ 'format': OCPPValueFormat.RAW,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'location': OCPPLocation.OUTLET,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
}
]
},
@@ -810,43 +813,44 @@ export default class OCPPCommonTests {
'timestamp': this.transactionCurrentTime.toISOString(),
'sampledValue': [
{
- 'value': stopValue,
- 'context': 'Transaction.End',
- 'format': 'Raw',
- 'measurand': 'Energy.Active.Import.Register',
- 'location': 'Outlet',
- 'unit': 'Wh'
+ 'value': stopValue.toString(),
+ 'context': OCPPReadingContext.TRANSACTION_END,
+ 'format': OCPPValueFormat.RAW,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'location': OCPPLocation.OUTLET,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
}
]
}
];
+ // OCPP 1.5
} else {
transactionData = {
'values': [
{
'timestamp': this.transactionStartTime.toISOString(),
'value': {
- 'attributes': {
- 'context': 'Transaction.Begin',
- 'format': 'Raw',
- 'location': 'Outlet',
- 'measurand': 'Energy.Active.Import.Register',
- 'unit': 'Wh'
+ '$attributes': {
+ 'context': OCPPReadingContext.TRANSACTION_BEGIN,
+ 'format': OCPPValueFormat.RAW,
+ 'location': OCPPLocation.OUTLET,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
},
- '$value': this.transactionStartMeterValue,
+ '$value': this.transactionStartMeterValue.toString(),
}
},
{
'timestamp': this.transactionCurrentTime.toISOString(),
'value': {
- 'attributes': {
- 'context': 'Transaction.End',
- 'format': 'Raw',
- 'location': 'Outlet',
- 'measurand': 'Energy.Active.Import.Register',
- 'unit': 'Wh'
+ '$attributes': {
+ 'context': OCPPReadingContext.TRANSACTION_END,
+ 'format': OCPPValueFormat.RAW,
+ 'location': OCPPLocation.OUTLET,
+ 'measurand': OCPPMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+ 'unit': OCPPUnitOfMeasure.WATT_HOUR
},
- '$value': stopValue
+ '$value': stopValue.toString()
}
}
]
@@ -867,20 +871,20 @@ export default class OCPPCommonTests {
expect(bootNotification.status).to.eql('Accepted');
expect(bootNotification).to.have.property('currentTime');
let chargingStationResponse = await this.chargingStationContext.readChargingStation();
- if (this.chargingStationContext.getChargingStation().ocppVersion === '1.6') {
+ if (this.chargingStationContext.getChargingStation().ocppVersion === OCPPVersion.VERSION_16) {
expect(bootNotification.currentTime).to.equal(chargingStationResponse.data.lastReboot);
} else {
expect((bootNotification.currentTime as unknown as Date).toISOString()).to.equal(chargingStationResponse.data.lastReboot);
}
const bootNotification2 = await this.chargingStationContext.sendBootNotification();
chargingStationResponse = await this.chargingStationContext.readChargingStation();
- if (this.chargingStationContext.getChargingStation().ocppVersion === '1.6') {
+ if (this.chargingStationContext.getChargingStation().ocppVersion === OCPPVersion.VERSION_16) {
expect(bootNotification2.currentTime).to.equal(chargingStationResponse.data.lastReboot);
} else {
expect((bootNotification2.currentTime as unknown as Date).toISOString()).to.equal(chargingStationResponse.data.lastReboot);
}
expect(bootNotification.currentTime).to.not.equal(bootNotification2.currentTime);
- if (this.chargingStationContext.getChargingStation().ocppVersion === '1.6') {
+ if (this.chargingStationContext.getChargingStation().ocppVersion === OCPPVersion.VERSION_16) {
expect(new Date(bootNotification.currentTime)).to.beforeTime(new Date(bootNotification2.currentTime));
} else {
expect(bootNotification.currentTime).to.beforeTime(new Date(bootNotification2.currentTime));

MODIFY
test/api/context/ChargingStationContext.ts
test/api/context/ChargingStationContext.ts
-import { ChargePointErrorCode, ChargePointStatus, OCPP15MeterValuesRequest, OCPPAuthorizeResponse, OCPPBootNotificationResponse, OCPPDataTransferResponse, OCPPFirmwareStatus, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatResponse, OCPPLocation, OCPPMeasurand, OCPPMeterValuesRequest, OCPPMeterValuesResponse, OCPPReadingContext, OCPPStartTransactionResponse, OCPPStatusNotificationRequest, OCPPStatusNotificationResponse, OCPPStopTransactionResponse, OCPPUnitOfMeasure, OCPPValueFormat } from '../../../src/types/ocpp/OCPPServer';
+import { ChargePointErrorCode, ChargePointStatus, OCPP15MeterValuesRequest, OCPP15TransactionData, OCPPAuthorizeResponse, OCPPBootNotificationResponse, OCPPDataTransferResponse, OCPPFirmwareStatus, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatResponse, OCPPLocation, OCPPMeasurand, OCPPMeterValue, OCPPMeterValuesRequest, OCPPMeterValuesResponse, OCPPReadingContext, OCPPStartTransactionResponse, OCPPStatusNotificationRequest, OCPPStatusNotificationResponse, OCPPStopTransactionResponse, OCPPUnitOfMeasure, OCPPValueFormat, OCPPVersion } from '../../../src/types/ocpp/OCPPServer';
import CentralServerService from '../client/CentralServerService';
import ChargingStation from '../../types/ChargingStation';
@@ -13,14 +13,12 @@ export default class ChargingStationContext {
private chargingStation: ChargingStation;
private ocppService: OCPPService;
private tenantContext: TenantContext;
- private transactionsStarted: any;
- private transactionsStopped: any;
+ private transactionsStarted: OCPPStartTransactionResponse[] = [];
+ private transactionsStopped: OCPPStopTransactionResponse[] = [];
constructor(chargingStation, tenantContext) {
this.chargingStation = chargingStation;
this.tenantContext = tenantContext;
- this.transactionsStarted = [];
- this.transactionsStopped = [];
}
async initialize(token: string = null) {
@@ -30,9 +28,14 @@ export default class ChargingStationContext {
async cleanUpCreatedData() {
// Clean up transactions
for (const transaction of this.transactionsStarted) {
+ if (transaction.transactionId) {
+ const transactionResponse = await this.tenantContext.getAdminCentralServerService().transactionApi.readById(transaction.transactionId);
+ if (transactionResponse.status === 200) {
await this.tenantContext.getAdminCentralServerService().transactionApi.delete(transaction.transactionId);
}
}
+ }
+ }
getChargingStation() {
return this.chargingStation;
@@ -76,7 +79,8 @@ export default class ChargingStationContext {
return response;
}
- async stopTransaction(transactionId: number, tagId: string, meterStop: number, stopDate: Date, transactionData?: any): Promise<OCPPStopTransactionResponse> {
+ async stopTransaction(transactionId: number, tagId: string, meterStop: number, stopDate: Date, transactionData?: OCPPMeterValue[] | OCPP15TransactionData): Promise<OCPPStopTransactionResponse> {
+ // Check props
const response = await this.ocppService.executeStopTransaction(this.chargingStation.id, {
transactionId: transactionId,
idTag: tagId,
@@ -90,11 +94,21 @@ export default class ChargingStationContext {
return response;
}
+ public removeTransaction(transactionId: number) {
+ for (let i = 0; i < this.transactionsStarted.length; i++) {
+ const transaction = this.transactionsStarted[i];
+ if (transaction.transactionId === transactionId) {
+ this.transactionsStarted.splice(i, 1);
+ break;
+ }
+ }
+ }
+
async sendConsumptionMeterValue(connectorId: number, transactionId: number, meterEnergyValue: number,
timestamp: Date, withSoC = false, meterSocValue = 0): Promise<OCPPMeterValuesResponse> {
let meterValueRequest: OCPPMeterValuesRequest | OCPP15MeterValuesRequest;
// OCPP 1.6?
- if (this.chargingStation.ocppVersion === '1.6') {
+ if (this.chargingStation.ocppVersion === OCPPVersion.VERSION_16) {
// Energy
meterValueRequest = {
connectorId: connectorId,
@@ -163,7 +177,7 @@ export default class ChargingStationContext {
signedValue: string, timestamp, withSoC = false, withSignedData = false): Promise<OCPPMeterValuesResponse> {
let meterValueRequest: OCPPMeterValuesRequest | OCPP15MeterValuesRequest;
// OCPP 1.6?
- if (this.chargingStation.ocppVersion === '1.6') {
+ if (this.chargingStation.ocppVersion === OCPPVersion.VERSION_16) {
// Energy
meterValueRequest = {
connectorId: connectorId,
@@ -195,15 +209,17 @@ export default class ChargingStationContext {
context: context,
});
}
+ // OCPP 1.5
+ } else if (this.chargingStation.ocppVersion === OCPPVersion.VERSION_15) {
+ // Do Nothing
}
- // Nothing for OCPP 1.5
return this.ocppService.executeMeterValues(this.chargingStation.id, meterValueRequest);
}
async sendClockMeterValue(connectorId: number, transactionId: number, meterValue: number, timestamp: Date): Promise<OCPPMeterValuesResponse> {
let response: OCPPMeterValuesResponse;
// OCPP 1.6?
- if (this.chargingStation.ocppVersion === '1.6') {
+ if (this.chargingStation.ocppVersion === OCPPVersion.VERSION_16) {
response = await this.ocppService.executeMeterValues(this.chargingStation.id, {
connectorId: connectorId,
transactionId: transactionId,

MODIFY
test/api/context/ContextDefinition.ts
test/api/context/ContextDefinition.ts
import { AnalyticsSettingsType, BillingSettingsType, PricingSettingsType, RefundSettingsType, RoamingSettingsType, SettingDBContent, SmartChargingSettingsType } from '../../../src/types/Setting';
+import { OCPPVersion } from '../../../src/types/ocpp/OCPPServer';
import faker from 'faker';
export interface TenantDefinition {
@@ -551,7 +552,7 @@ export default class ContextDefinition {
static readonly TENANT_CHARGING_STATION_LIST: any = [
{
baseName: ContextDefinition.CHARGING_STATION_CONTEXTS.ASSIGNED_OCPP16, // Concatenated with siteAreaName
- ocppVersion: '1.6',
+ ocppVersion: OCPPVersion.VERSION_16,
siteAreaNames: [
`${ContextDefinition.SITE_CONTEXTS.SITE_BASIC}-${ContextDefinition.SITE_AREA_CONTEXTS.WITH_ACL}`,
`${ContextDefinition.SITE_CONTEXTS.SITE_BASIC}-${ContextDefinition.SITE_AREA_CONTEXTS.WITHOUT_ACL}`,
@@ -562,7 +563,7 @@ export default class ContextDefinition {
},
{
baseName: ContextDefinition.CHARGING_STATION_CONTEXTS.ASSIGNED_OCPP15, // Concatenated with siteAreaName
- ocppVersion: '1.5',
+ ocppVersion: OCPPVersion.VERSION_15,
siteAreaNames: [
`${ContextDefinition.SITE_CONTEXTS.SITE_BASIC}-${ContextDefinition.SITE_AREA_CONTEXTS.WITH_ACL}`,
`${ContextDefinition.SITE_CONTEXTS.SITE_BASIC}-${ContextDefinition.SITE_AREA_CONTEXTS.WITHOUT_ACL}`,
@@ -573,12 +574,12 @@ export default class ContextDefinition {
},
{
baseName: ContextDefinition.CHARGING_STATION_CONTEXTS.UNASSIGNED_OCPP16,
- ocppVersion: '1.6',
+ ocppVersion: OCPPVersion.VERSION_16,
siteAreaNames: null,
},
{
baseName: ContextDefinition.CHARGING_STATION_CONTEXTS.UNASSIGNED_OCPP15,
- ocppVersion: '1.5',
+ ocppVersion: OCPPVersion.VERSION_15,
siteAreaNames: null,
}
];

MODIFY
test/api/context/ContextProvider.ts
test/api/context/ContextProvider.ts
@@ -4,6 +4,7 @@ import CentralServerService from '../client/CentralServerService';
import Constants from '../../../src/utils/Constants';
import ContextDefinition from './ContextDefinition';
import Factory from '../../factories/Factory';
+import { OCPPVersion } from '../../../src/types/ocpp/OCPPServer';
import SiteContext from './SiteContext';
import TenantComponents from '../../../src/types/TenantComponents';
import TenantContext from './TenantContext';
@@ -132,13 +133,13 @@ export default class ContextProvider {
}
const registrationToken = faker.random.alphaNumeric(10);
- const unregisteredChargingStation15 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.UNREGISTERED_OCPP15, ocppVersion: '1.5' });
+ const unregisteredChargingStation15 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.UNREGISTERED_OCPP15, ocppVersion: OCPPVersion.VERSION_15 });
await newTenantContext.addChargingStation(unregisteredChargingStation15, registrationToken);
- const unregisteredChargingStation16 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.UNREGISTERED_OCPP16, ocppVersion: '1.6' });
+ const unregisteredChargingStation16 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.UNREGISTERED_OCPP16, ocppVersion: OCPPVersion.VERSION_16 });
await newTenantContext.addChargingStation(unregisteredChargingStation16, registrationToken);
- const invalidChargingStation15 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.INVALID_IDENTIFIER_OCPP15, ocppVersion: '1.5' });
+ const invalidChargingStation15 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.INVALID_IDENTIFIER_OCPP15, ocppVersion: OCPPVersion.VERSION_15 });
await newTenantContext.addChargingStation(invalidChargingStation15);
- const invalidChargingStation16 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.INVALID_IDENTIFIER_OCPP16, ocppVersion: '1.6' });
+ const invalidChargingStation16 = await Factory.chargingStation.build({ id: ContextDefinition.CHARGING_STATION_CONTEXTS.INVALID_IDENTIFIER_OCPP16, ocppVersion: OCPPVersion.VERSION_16 });
await newTenantContext.addChargingStation(invalidChargingStation16);
return newTenantContext;

MODIFY
test/api/context/TenantContext.ts
test/api/context/TenantContext.ts
@@ -5,6 +5,7 @@ import Factory from '../../factories/Factory';
import OCPPJsonService15 from '../ocpp/soap/OCPPSoapService15';
import OCPPJsonService16 from '../ocpp/json/OCPPJsonService16';
import OCPPService from '../ocpp/OCPPService';
+import { OCPPVersion } from '../../../src/types/ocpp/OCPPServer';
import SiteAreaContext from './SiteAreaContext';
import SiteContext from './SiteContext';
import Tenant from '../../types/Tenant';
@@ -67,9 +68,9 @@ export default class TenantContext {
if (!this.ocpp15 || !this.ocpp16 || token) {
await this.initialize(token);
}
- if (ocppVersion === '1.6') {
+ if (ocppVersion === OCPPVersion.VERSION_16) {
return this.ocpp16;
- } else if (ocppVersion === '1.5') {
+ } else if (ocppVersion === OCPPVersion.VERSION_15) {
return this.ocpp15;
}
throw new Error('unknown ocpp version');

MODIFY
test/api/ocpp/soap/OCPPSoapService15.ts
test/api/ocpp/soap/OCPPSoapService15.ts
-import { OCPP15MeterValuesRequest, OCPPAuthorizeRequest, OCPPAuthorizeResponse, OCPPBootNotificationRequest, OCPPBootNotificationResponse, OCPPDataTransferRequest, OCPPDataTransferResponse, OCPPDiagnosticsStatusNotificationRequest, OCPPDiagnosticsStatusNotificationResponse, OCPPFirmwareStatusNotificationRequest, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatRequest, OCPPHeartbeatResponse, OCPPMeterValuesRequest, OCPPMeterValuesResponse, OCPPStartTransactionRequest, OCPPStartTransactionResponse, OCPPStatusNotificationRequest, OCPPStatusNotificationResponse, OCPPStopTransactionRequest, OCPPStopTransactionResponse } from '../../../../src/types/ocpp/OCPPServer';
+import { OCPP15MeterValuesRequest, OCPPAuthorizeRequest, OCPPAuthorizeResponse, OCPPBootNotificationRequest, OCPPBootNotificationResponse, OCPPDataTransferRequest, OCPPDataTransferResponse, OCPPDiagnosticsStatusNotificationRequest, OCPPDiagnosticsStatusNotificationResponse, OCPPFirmwareStatusNotificationRequest, OCPPFirmwareStatusNotificationResponse, OCPPHeartbeatRequest, OCPPHeartbeatResponse, OCPPMeterValuesRequest, OCPPMeterValuesResponse, OCPPStartTransactionRequest, OCPPStartTransactionResponse, OCPPStatusNotificationRequest, OCPPStatusNotificationResponse, OCPPStopTransactionRequest, OCPPStopTransactionResponse, OCPPVersion } from '../../../../src/types/ocpp/OCPPServer';
import OCPPService from '../OCPPService';
import soap from 'strong-soap';
@@ -13,7 +13,7 @@ export default class OCPPSoapService15 extends OCPPService {
}
public getVersion() {
- return '1.5';
+ return OCPPVersion.VERSION_15;
}
public async executeAuthorize(chargingStationID: string, authorize: OCPPAuthorizeRequest): Promise<OCPPAuthorizeResponse> {

Fixed OCPP wrong typing + Typed TransactionData + Enhanced logs + use Constants