]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
fix(ocpp): check connector availability in RemoteStartTransaction auto-selection...
authorRishabh Vaish <rishabhvaish.904@gmail.com>
Sun, 5 Apr 2026 15:08:24 +0000 (08:08 -0700)
committerGitHub <noreply@github.com>
Sun, 5 Apr 2026 15:08:24 +0000 (17:08 +0200)
* fix(ocpp): check connector availability in RemoteStartTransaction auto-selection

The OCPP 1.6 RemoteStartTransaction handler's connector auto-selection
(when connectorId is omitted) only checked transactionStarted and
reservation status but not administrative availability. This meant an
Inoperative connector could be selected, causing the request to be
rejected even when other Operative connectors were free.

Added isConnectorAvailable() check to the auto-selection loop, matching
the behavior already present in the OCPP 2.0 selectAvailableEvse().

* [autofix.ci] apply automated fixes

* Update tests/charging-station/ocpp/1.6/OCPP16IncomingRequestService-RemoteStartTransaction.test.ts

* Apply suggestion from @jerome-benoit

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
tests/charging-station/ocpp/1.6/OCPP16IncomingRequestService-RemoteStartTransaction.test.ts

index e3f16aa7f8dc57aa4b180c5f2d108a631a2438b0..3718e774e007988beaa629b157572ccf88f310db 100644 (file)
@@ -1228,6 +1228,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         connectorId++
       ) {
         if (
+          chargingStation.isConnectorAvailable(connectorId) &&
           chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false &&
           !OCPP16ServiceUtils.hasReservation(chargingStation, connectorId, commandPayload.idTag)
         ) {
index 40dd71d6f608ae2320d15204bc0b6dadd9b89a49..bcf40e75c93261883e995bc04ad5796bcb5ab396 100644 (file)
@@ -155,6 +155,57 @@ await describe('OCPP16IncomingRequestService — RemoteStartTransaction', async
     assert.strictEqual(response.status, GenericStatus.Rejected)
   })
 
+  // @spec §5.11 — Auto-select skips Inoperative connectors
+  await it('should skip inoperative connectors during auto-selection without connectorId', async () => {
+    // Arrange
+    const { station, testableService } = testContext
+
+    // Set connector 1 to Inoperative
+    const connector1Status = station.getConnectorStatus(1)
+    if (connector1Status != null) {
+      connector1Status.availability = AvailabilityType.Inoperative
+    }
+
+    const request: RemoteStartTransactionRequest = {
+      idTag: TEST_ID_TAG,
+    }
+
+    // Act
+    const response = await testableService.handleRequestRemoteStartTransaction(station, request)
+
+    // Assert — should select connector 2 (which is Operative) and accept
+    assert.strictEqual(response.status, GenericStatus.Accepted)
+    assert.strictEqual(
+      request.connectorId,
+      2,
+      'should auto-select connector 2 since connector 1 is Inoperative'
+    )
+  })
+
+  // @spec §5.11 — All connectors Inoperative, no connectorId specified
+  await it('should reject remote start transaction when all connectors are inoperative and no connectorId specified', async () => {
+    // Arrange
+    const { station, testableService } = testContext
+
+    // Set all connectors to Inoperative
+    for (let connectorId = 1; connectorId <= station.getNumberOfConnectors(); connectorId++) {
+      const connectorStatus = station.getConnectorStatus(connectorId)
+      if (connectorStatus != null) {
+        connectorStatus.availability = AvailabilityType.Inoperative
+      }
+    }
+
+    const request: RemoteStartTransactionRequest = {
+      idTag: TEST_ID_TAG,
+    }
+
+    // Act
+    const response = await testableService.handleRequestRemoteStartTransaction(station, request)
+
+    // Assert
+    assert.strictEqual(response.status, GenericStatus.Rejected)
+  })
+
   // @spec §5.11 — Non-existing connector
   await it('should reject remote start transaction with non-existing connectorId', async () => {
     // Arrange