From: Jérôme Benoit Date: Sun, 9 Nov 2025 18:22:46 +0000 (+0100) Subject: fix: properly resolve evse id X-Git-Tag: v2~51^2~9 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=8ad81d3454c0c4599123ec954a982a7804c45eb8;p=e-mobility-charging-stations-simulator.git fix: properly resolve evse id Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index cf1a9f81..125f10de 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -487,6 +487,18 @@ export class ChargingStation extends EventEmitter { ) } + public getEvseIdByConnectorId (connectorId: number): number | undefined { + if (!this.hasEvses) { + return undefined + } + for (const [evseId, evseStatus] of this.evses) { + if (evseStatus.connectors.has(connectorId)) { + return evseId + } + } + return undefined + } + public getHeartbeatInterval (): number { const HeartbeatInterval = getConfigurationKey(this, StandardParametersKey.HeartbeatInterval) if (HeartbeatInterval != null) { diff --git a/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts b/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts index 11c1ab1c..5e48dd0c 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts @@ -109,7 +109,7 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { ) } - public static async requestStopTransaction( + public static async requestStopTransaction ( chargingStation: ChargingStation, connectorId: number ): Promise { @@ -133,10 +133,18 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils { return OCPP20Constants.OCPP_RESPONSE_REJECTED } + const evseId = chargingStation.getEvseIdByConnectorId(connectorId) + if (evseId == null) { + logger.error( + `${chargingStation.logPrefix()} OCPP20ServiceUtils.requestStopTransaction: Cannot find EVSE ID for connector ${connectorId.toString()}` + ) + return OCPP20Constants.OCPP_RESPONSE_REJECTED + } + const transactionEventRequest: OCPP20TransactionEventRequest = { eventType: OCPP20TransactionEventEnumType.Ended, evse: { - id: connectorId, + id: evseId, }, seqNo: 0, // This should be managed by the transaction sequence timestamp: new Date(), diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index df70b9b1..c82e9a7e 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -114,7 +114,7 @@ const buildStatusNotificationRequest = ( connectorId, connectorStatus: status as OCPP20ConnectorStatusEnumType, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - evseId: evseId!, + evseId: evseId ?? chargingStation.getEvseIdByConnectorId(connectorId)!, timestamp: new Date(), } satisfies OCPP20StatusNotificationRequest default: diff --git a/tests/ChargingStationFactory.test.ts b/tests/ChargingStationFactory.test.ts index f01cef39..a99753ae 100644 --- a/tests/ChargingStationFactory.test.ts +++ b/tests/ChargingStationFactory.test.ts @@ -469,6 +469,61 @@ await describe('ChargingStationFactory', async () => { }) }) + await describe('getEvseIdByConnectorId', async () => { + await it('Should return undefined for stations without EVSEs', () => { + const station = createChargingStation({ + connectorsCount: 3, + stationInfo: { ocppVersion: OCPPVersion.VERSION_16 }, // OCPP 1.6 doesn't use EVSEs + }) + + expect(station.getEvseIdByConnectorId(1)).toBeUndefined() + expect(station.getEvseIdByConnectorId(2)).toBeUndefined() + }) + + await it('Should return correct EVSE ID for connectors in EVSE mode', () => { + const station = createChargingStation({ + connectorsCount: 6, + evseConfiguration: { evsesCount: 2 }, // 2 EVSEs with 3 connectors each + stationInfo: { ocppVersion: OCPPVersion.VERSION_201 }, + }) + + // EVSE 1 should have connectors 1, 2, 3 + expect(station.getEvseIdByConnectorId(1)).toBe(1) + expect(station.getEvseIdByConnectorId(2)).toBe(1) + expect(station.getEvseIdByConnectorId(3)).toBe(1) + + // EVSE 2 should have connectors 4, 5, 6 + expect(station.getEvseIdByConnectorId(4)).toBe(2) + expect(station.getEvseIdByConnectorId(5)).toBe(2) + expect(station.getEvseIdByConnectorId(6)).toBe(2) + }) + + await it('Should return undefined for non-existent connector IDs', () => { + const station = createChargingStation({ + connectorsCount: 4, + evseConfiguration: { evsesCount: 2 }, + stationInfo: { ocppVersion: OCPPVersion.VERSION_201 }, + }) + + expect(station.getEvseIdByConnectorId(0)).toBeUndefined() // Connector 0 not in EVSEs + expect(station.getEvseIdByConnectorId(99)).toBeUndefined() // Non-existent connector + expect(station.getEvseIdByConnectorId(-1)).toBeUndefined() // Invalid connector ID + }) + + await it('Should handle single EVSE with multiple connectors', () => { + const station = createChargingStation({ + connectorsCount: 3, + evseConfiguration: { evsesCount: 1 }, // Single EVSE with all connectors + stationInfo: { ocppVersion: OCPPVersion.VERSION_201 }, + }) + + // All connectors should belong to EVSE 1 + expect(station.getEvseIdByConnectorId(1)).toBe(1) + expect(station.getEvseIdByConnectorId(2)).toBe(1) + expect(station.getEvseIdByConnectorId(3)).toBe(1) + }) + }) + await describe('isConnectorAvailable', async () => { await it('Should return false for connector ID 0', () => { const station = createChargingStation({ connectorsCount: 2 }) diff --git a/tests/ChargingStationFactory.ts b/tests/ChargingStationFactory.ts index 5bda606a..4a7a2b8e 100644 --- a/tests/ChargingStationFactory.ts +++ b/tests/ChargingStationFactory.ts @@ -111,6 +111,17 @@ export function createChargingStation (options: ChargingStationOptions = {}): Ch } return chargingStation.connectors.get(connectorId) }, + getEvseIdByConnectorId: (connectorId: number) => { + if (!chargingStation.hasEvses) { + return undefined + } + for (const [evseId, evseStatus] of chargingStation.evses.entries()) { + if (evseStatus.connectors.has(connectorId)) { + return evseId + } + } + return undefined + }, getEvseIdByTransactionId: (transactionId: string) => { // Search through EVSEs to find one with matching transaction ID if (chargingStation.hasEvses) {