Handle parking time with all possible status' transitions
MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
@@ -1005,27 +1005,26 @@ export default class OCPPService {
private async checkStatusNotificationExtraInactivity(tenantID: string, chargingStation: ChargingStation,
statusNotification: OCPPStatusNotificationRequestExtended, connector: Connector) {
// Check Inactivity
- // OCPP 1.6: Finishing --> Available
- if (connector.status === ChargePointStatus.FINISHING &&
- statusNotification.status === ChargePointStatus.AVAILABLE &&
+ if (statusNotification.status === ChargePointStatus.AVAILABLE &&
Utils.objectHasProperty(statusNotification, 'timestamp')) {
// Get the last transaction
const lastTransaction = await TransactionStorage.getLastTransaction(
tenantID, chargingStation.id, connector.connectorId);
// Session is finished
- if (lastTransaction && lastTransaction.stop) {
- // Inactivity already computed
- if (!lastTransaction.stop.extraInactivityComputed) {
- const transactionStopTimestamp = lastTransaction.stop.timestamp;
- const statusNotifTimestamp = new Date(statusNotification.timestamp);
+ if (lastTransaction && lastTransaction.stop && !lastTransaction.stop.extraInactivityComputed) {
+ const transactionStopTimestamp = Utils.convertToDate(lastTransaction.stop.timestamp);
+ const currentStatusNotifTimestamp = Utils.convertToDate(statusNotification.timestamp);
+ // Diff
lastTransaction.stop.extraInactivitySecs =
- Math.floor((statusNotifTimestamp.getTime() - transactionStopTimestamp.getTime()) / 1000);
+ Math.floor((currentStatusNotifTimestamp.getTime() - transactionStopTimestamp.getTime()) / 1000);
+ // Flag
lastTransaction.stop.extraInactivityComputed = true;
+ // Fix the Inactivity severity
lastTransaction.stop.inactivityStatus = Utils.getInactivityStatusLevel(lastTransaction.chargeBox, lastTransaction.connectorId,
lastTransaction.stop.totalInactivitySecs + lastTransaction.stop.extraInactivitySecs);
// Build extra inactivity consumption
await OCPPUtils.buildExtraConsumptionInactivity(tenantID, lastTransaction);
- // OCPI: post CDR
+ // OCPI: Post the CDR
await OCPPUtils.processOCPITransaction(tenantID, lastTransaction, chargingStation, TransactionAction.END);
// Save
await TransactionStorage.saveTransaction(tenantID, lastTransaction);
@@ -1037,44 +1036,7 @@ export default class OCPPService {
module: MODULE_NAME, method: 'checkStatusNotificationExtraInactivity',
action: ServerAction.EXTRA_INACTIVITY,
message: `Connector ID '${lastTransaction.connectorId}' > Transaction ID '${lastTransaction.id}' > Extra Inactivity of ${lastTransaction.stop.extraInactivitySecs} secs has been added`,
- detailedMessages: [statusNotification, lastTransaction]
- });
- } else {
- // Log
- Logging.logWarning({
- tenantID: tenantID,
- source: chargingStation.id,
- user: lastTransaction.userID,
- module: MODULE_NAME, method: 'checkStatusNotificationExtraInactivity',
- action: ServerAction.EXTRA_INACTIVITY,
- message: `Connector ID '${lastTransaction.connectorId}' > Transaction ID '${lastTransaction.id}' > Extra Inactivity has already been computed`,
- detailedMessages: [statusNotification, lastTransaction]
- });
- }
- }
- // OCPP 1.6: Charging --> Available
- } else if (connector.status === ChargePointStatus.CHARGING &&
- statusNotification.status === ChargePointStatus.AVAILABLE) {
- // Get the last transaction
- const lastTransaction = await TransactionStorage.getLastTransaction(
- tenantID, chargingStation.id, connector.connectorId);
- // FInished?
- if (lastTransaction && lastTransaction.stop && !lastTransaction.stop.extraInactivityComputed) {
- // Marked done
- lastTransaction.stop.extraInactivityComputed = true;
- // OCPI: post CDR
- await OCPPUtils.processOCPITransaction(tenantID, lastTransaction, chargingStation, TransactionAction.END);
- // Save
- await TransactionStorage.saveTransaction(tenantID, lastTransaction);
- // Log
- Logging.logInfo({
- tenantID: tenantID,
- source: chargingStation.id,
- user: lastTransaction.userID,
- module: MODULE_NAME, method: 'checkStatusNotificationExtraInactivity',
- action: ServerAction.EXTRA_INACTIVITY,
- message: `Connector ID '${lastTransaction.connectorId}' > Transaction ID '${lastTransaction.id}' > No Extra Inactivity has been added`,
- detailedMessages: [statusNotification, lastTransaction]
+ detailedMessages: [statusNotification, connector, lastTransaction]
});
}
}

MODIFY
src/storage/mongodb/ChargingStationStorage.ts
src/storage/mongodb/ChargingStationStorage.ts
+import { ChargePointStatus, OCPPFirmwareStatus } from '../../types/ocpp/OCPPServer';
import { ChargingProfile, ChargingProfilePurposeType, ChargingRateUnitType } from '../../types/ChargingProfile';
-import ChargingStation, { ChargePoint, ChargingStationOcppParameters, ChargingStationTemplate, Connector, ConnectorMDB, ConnectorType, OcppParameter } from '../../types/ChargingStation';
+import ChargingStation, { ChargePoint, ChargingStationOcppParameters, ChargingStationTemplate, Connector, ConnectorType, CurrentType, OcppParameter, PhaseAssignmentToGrid, Voltage } from '../../types/ChargingStation';
import { ChargingStationInError, ChargingStationInErrorType } from '../../types/InError';
-import { GridFSBucket, GridFSBucketReadStream, GridFSBucketWriteStream } from 'mongodb';
+import { GridFSBucket, GridFSBucketReadStream, GridFSBucketWriteStream, ObjectID } from 'mongodb';
import global, { FilterParams } from '../../types/GlobalType';
import BackendError from '../../exception/BackendError';
@@ -11,8 +12,8 @@ import Cypher from '../../utils/Cypher';
import { DataResult } from '../../types/DataResult';
import DatabaseUtils from './DatabaseUtils';
import DbParams from '../../types/database/DbParams';
+import { InactivityStatus } from '../../types/Transaction';
import Logging from '../../utils/Logging';
-import { OCPPFirmwareStatus } from '../../types/ocpp/OCPPServer';
import { ServerAction } from '../../types/Server';
import TenantComponents from '../../types/TenantComponents';
import TenantStorage from './TenantStorage';
@@ -22,6 +23,33 @@ import moment from 'moment';
const MODULE_NAME = 'ChargingStationStorage';
+export interface ConnectorMDB {
+ connectorId: number;
+ currentInstantWatts: number;
+ currentStateOfCharge: number;
+ currentTotalConsumptionWh: number;
+ currentTotalInactivitySecs: number;
+ currentInactivityStatus: InactivityStatus;
+ currentTransactionID: number;
+ currentTransactionDate: Date;
+ currentTagID: string;
+ status: ChargePointStatus;
+ errorCode: string;
+ info: string;
+ vendorErrorCode: string;
+ power: number;
+ type: ConnectorType;
+ voltage: Voltage;
+ amperage: number;
+ amperageLimit: number;
+ userID: ObjectID;
+ statusLastChangedOn: Date;
+ numberOfConnectedPhase: number;
+ currentType: CurrentType;
+ chargePointID: number;
+ phaseAssignmentToGrid: PhaseAssignmentToGrid;
+}
+
export default class ChargingStationStorage {
public static async updateChargingStationTemplatesFromFile(): Promise<void> {
@@ -488,9 +516,9 @@ export default class ChargingStationStorage {
powerLimitUnit: chargingStationToSave.powerLimitUnit,
voltage: Utils.convertToInt(chargingStationToSave.voltage),
connectors: chargingStationToSave.connectors ? chargingStationToSave.connectors.map(
- (connector) => ChargingStationStorage.connector2connectorMDB(connector)) : [],
+ (connector) => ChargingStationStorage.filterConnectorMDB(connector)) : [],
chargePoints: chargingStationToSave.chargePoints ? chargingStationToSave.chargePoints.map(
- (chargePoint) => ChargingStationStorage.chargePoint2ChargePointMDB(chargePoint)) : [],
+ (chargePoint) => ChargingStationStorage.filterChargePointMDB(chargePoint)) : [],
coordinates: Utils.containsGPSCoordinates(chargingStationToSave.coordinates) ? chargingStationToSave.coordinates.map(
(coordinate) => Utils.convertToFloat(coordinate)) : [],
remoteAuthorizations: chargingStationToSave.remoteAuthorizations ? chargingStationToSave.remoteAuthorizations : [],
@@ -516,7 +544,7 @@ export default class ChargingStationStorage {
// Debug
const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'saveChargingStationConnector');
// Ensure good typing
- const connectorMDB = ChargingStationStorage.connector2connectorMDB(connector);
+ const connectorMDB = ChargingStationStorage.filterConnectorMDB(connector);
// Check Tenant
await Utils.checkTenant(tenantID);
const updatedFields: any = {};
@@ -913,11 +941,9 @@ export default class ChargingStationStorage {
}
}
- private static connector2connectorMDB(connector: Connector): ConnectorMDB {
- if (!connector) {
- return null;
- }
- return {
+ private static filterConnectorMDB(connector: Connector): ConnectorMDB {
+ if (connector) {
+ const newConnector: ConnectorMDB = {
connectorId: Utils.convertToInt(connector.connectorId),
currentInstantWatts: Utils.convertToFloat(connector.currentInstantWatts),
currentStateOfCharge: connector.currentStateOfCharge,
@@ -936,7 +962,7 @@ export default class ChargingStationStorage {
amperageLimit: connector.amperageLimit,
currentTransactionID: Utils.convertToInt(connector.currentTransactionID),
userID: Utils.convertToObjectID(connector.userID),
- statusLastChangedOn: connector.statusLastChangedOn,
+ statusLastChangedOn: Utils.convertToDate(connector.statusLastChangedOn),
currentInactivityStatus: connector.currentInactivityStatus,
numberOfConnectedPhase: connector.numberOfConnectedPhase,
currentType: connector.currentType,
@@ -948,12 +974,13 @@ export default class ChargingStationStorage {
csPhaseL3: connector.phaseAssignmentToGrid.csPhaseL3,
} : null,
};
+ return newConnector;
}
-
- private static chargePoint2ChargePointMDB(chargePoint: ChargePoint): ChargePoint {
- if (!chargePoint) {
return null;
}
+
+ private static filterChargePointMDB(chargePoint: ChargePoint): ChargePoint {
+ if (chargePoint) {
return {
chargePointID: Utils.convertToInt(chargePoint.chargePointID),
currentType: chargePoint.currentType,
@@ -969,4 +996,6 @@ export default class ChargingStationStorage {
connectorIDs: chargePoint.connectorIDs.map((connectorID) => Utils.convertToInt(connectorID)),
};
}
+ return null;
+ }
}

MODIFY
src/types/ChargingStation.ts
src/types/ChargingStation.ts
@@ -5,7 +5,6 @@ import CreatedUpdatedProps from './CreatedUpdatedProps';
import { InactivityStatus } from './Transaction';
import { KeyValue } from './GlobalType';
import { OCPIEvse } from './ocpi/OCPIEvse';
-import { ObjectID } from 'mongodb';
import SiteArea from './SiteArea';
import User from './User';
@@ -118,35 +117,6 @@ export interface Connector {
phaseAssignmentToGrid?: PhaseAssignmentToGrid;
}
-export interface ConnectorMDB {
- id?: string;
- connectorId: number;
- currentInstantWatts?: number;
- currentStateOfCharge?: number;
- currentTotalConsumptionWh?: number;
- currentTotalInactivitySecs?: number;
- currentInactivityStatus?: InactivityStatus;
- currentTransactionID?: number;
- currentTransactionDate?: Date;
- currentTagID?: string;
- status: ChargePointStatus;
- errorCode?: string;
- info?: string;
- vendorErrorCode?: string;
- power?: number;
- type?: ConnectorType;
- voltage?: Voltage;
- amperage?: number;
- amperageLimit?: number;
- userID?: ObjectID;
- user?: User;
- statusLastChangedOn?: Date;
- numberOfConnectedPhase?: number;
- currentType?: CurrentType;
- chargePointID?: number;
- phaseAssignmentToGrid?: PhaseAssignmentToGrid;
-}
-
export interface PhaseAssignmentToGrid {
csPhaseL1: OCPPPhase.L1 | OCPPPhase.L2 | OCPPPhase.L3;
csPhaseL2: OCPPPhase.L1 | OCPPPhase.L2 | OCPPPhase.L3;

MODIFY
test/api/OCPPCommonTests.ts
test/api/OCPPCommonTests.ts
@@ -585,7 +585,7 @@ export default class OCPPCommonTests {
expect(stopTransactionResponse.idTagInfo.status).to.equal(OCPPStatus.ACCEPTED);
// Set the connector to Available
this.chargingStationConnector1.status = ChargePointStatus.AVAILABLE;
- this.chargingStationConnector1.timestamp = new Date().toISOString();
+ this.chargingStationConnector1.timestamp = this.transactionCurrentTime.toISOString();
// Update
const statusResponse = await this.chargingStationContext.setConnectorStatus(this.chargingStationConnector1);
expect(statusResponse).to.eql({});

Handle parking time with all possible status' transitions