]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
feat(ui): allow to authorize RFID tag at start transaction
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 23 Jul 2025 19:27:10 +0000 (21:27 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 23 Jul 2025 19:27:10 +0000 (21:27 +0200)
closes #1476
closes #1475

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
README.md
src/charging-station/broadcast-channel/UIServiceWorkerBroadcastChannel.ts
src/types/UIProtocol.ts
ui/web/src/components/actions/StartTransaction.vue
ui/web/src/components/charging-stations/CSConnector.vue
ui/web/src/composables/UIClient.ts
ui/web/src/types/UIProtocol.ts

index c03b3f5e388197f395337b62047254a4ecc31f2d..410da5d19a50a6a138ad0f7a704d7e6e398908cc 100644 (file)
--- a/README.md
+++ b/README.md
@@ -848,6 +848,22 @@ Set the Websocket header _Sec-Websocket-Protocol_ to `ui0.0.1`.
 
 Examples:
 
+- **Authorize**
+- Request:  
+   `ProcedureName`: 'authorize'  
+   `PDU`: {  
+   `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),  
+   `idTag`: RFID tag string  
+   }
+
+- Response:  
+   `PDU`: {  
+   `status`: 'success' | 'failure',  
+   `hashIdsSucceeded`: charging station unique identifier strings array,  
+   `hashIdsFailed`: charging station unique identifier strings array (optional),  
+   `responsesFailed`: failed responses payload array (optional)  
+   }
+
 - **Start Transaction**
   - Request:  
     `ProcedureName`: 'startTransaction'  
index 48bf16915d39f17cfddc0ac39b6a4f03941326c8..12bc6824871d0ba10d42e252200e44ebd0a8111d 100644 (file)
@@ -34,16 +34,18 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
     const responsesStatus =
       this.responses
         .get(uuid)
-        ?.responses.every(({ status }) => status === ResponseStatus.SUCCESS) === true
+        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+        ?.responses.every(response => response?.status === ResponseStatus.SUCCESS) === true
         ? ResponseStatus.SUCCESS
         : ResponseStatus.FAILURE
     return {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
       hashIdsSucceeded: this.responses
         .get(uuid)
-        ?.responses.map(({ hashId, status }) => {
-          if (hashId != null && status === ResponseStatus.SUCCESS) {
-            return hashId
+        ?.responses.map(response => {
+          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+          if (response?.hashId != null && response?.status === ResponseStatus.SUCCESS) {
+            return response.hashId
           }
           return undefined
         })
@@ -53,9 +55,10 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
         hashIdsFailed: this.responses
           .get(uuid)
-          ?.responses.map(({ hashId, status }) => {
-            if (hashId != null && status === ResponseStatus.FAILURE) {
-              return hashId
+          ?.responses.map(response => {
+            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+            if (response?.hashId != null && response?.status === ResponseStatus.FAILURE) {
+              return response.hashId
             }
             return undefined
           })
@@ -66,7 +69,8 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
         responsesFailed: this.responses
           .get(uuid)
           ?.responses.map(response => {
-            if (response.status === ResponseStatus.FAILURE) {
+            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+            if (response?.status === ResponseStatus.FAILURE) {
               return response
             }
             return undefined
index 76e3ee7e3a78441378da4ceccfe6d356a4d2b7f1..9418d8be20eb1c14242c25695754f4526df070cb 100644 (file)
@@ -46,6 +46,7 @@ export enum Protocol {
 export enum ProtocolVersion {
   '0.0.1' = '0.0.1',
 }
+
 export enum ResponseStatus {
   FAILURE = 'failure',
   SUCCESS = 'success',
index d6829d46a6c88fd8725d40c44168a73b58ba2106..a4510948e9e533d62eda08e6e13d3d64a642d88c 100644 (file)
@@ -4,31 +4,70 @@
   </h1>
   <h2>{{ chargingStationId }}</h2>
   <h3>Connector {{ connectorId }}</h3>
-  <p>Scan RFID tag:</p>
-  <input
-    id="idtag"
-    v-model.trim="state.idTag"
-    name="idtag"
-    placeholder="RFID tag"
-    type="text"
-  >
+  <p>
+    RFID tag:
+    <input
+      id="idtag"
+      v-model.trim="state.idTag"
+      name="idtag"
+      placeholder="RFID tag"
+      type="text"
+    >
+  </p>
+  <p>
+    Authorize RFID tag:
+    <input
+      v-model="state.authorizeIdTag"
+      false-value="false"
+      true-value="true"
+      type="checkbox"
+    >
+  </p>
   <br>
   <Button
     id="action-button"
     @click="
       () => {
-        $uiClient
-          ?.startTransaction(hashId, convertToInt(connectorId), state.idTag)
-          .then(() => {
-            $toast.success('Transaction successfully started')
-          })
-          .catch((error: Error) => {
-            $toast.error('Error at starting transaction')
-            console.error('Error at starting transaction:', error)
-          })
-          .finally(() => {
-            $router.push({ name: 'charging-stations' })
-          })
+        state.authorizeIdTag = convertToBoolean(state.authorizeIdTag)
+        if (state.authorizeIdTag) {
+          if (state.idTag == null || state.idTag.trim().length === 0) {
+            $toast.error('Please provide an RFID tag to authorize')
+            return
+          }
+          $uiClient
+            ?.authorize(hashId, state.idTag)
+            .then(() => {
+              $uiClient
+                ?.startTransaction(hashId, convertToInt(connectorId), state.idTag)
+                .then(() => {
+                  $toast.success('Transaction successfully started')
+                })
+                .catch((error: Error) => {
+                  $toast.error('Error at starting transaction')
+                  console.error('Error at starting transaction:', error)
+                })
+                .finally(() => {
+                  $router.push({ name: 'charging-stations' })
+                })
+            })
+            .catch((error: Error) => {
+              $toast.error('Error at authorizing RFID tag')
+              console.error('Error at authorizing RFID tag:', error)
+            })
+        } else {
+          $uiClient
+            ?.startTransaction(hashId, convertToInt(connectorId), state.idTag)
+            .then(() => {
+              $toast.success('Transaction successfully started')
+            })
+            .catch((error: Error) => {
+              $toast.error('Error at starting transaction')
+              console.error('Error at starting transaction:', error)
+            })
+            .finally(() => {
+              $router.push({ name: 'charging-stations' })
+            })
+        }
       }
     "
   >
@@ -40,7 +79,7 @@
 import { ref } from 'vue'
 
 import Button from '@/components/buttons/Button.vue'
-import { convertToInt } from '@/composables'
+import { convertToBoolean, convertToInt } from '@/composables'
 
 defineProps<{
   chargingStationId: string
@@ -48,7 +87,8 @@ defineProps<{
   hashId: string
 }>()
 
-const state = ref<{ idTag: string }>({
+const state = ref<{ authorizeIdTag: boolean; idTag: string }>({
+  authorizeIdTag: false,
   idTag: '',
 })
 </script>
index a6a5729211ea4dbe4888a32cb0e675b1671553dc..8503d8f3b3de0c154a8f60286965c185e0f86a6d 100644 (file)
@@ -70,6 +70,10 @@ const uiClient = useUIClient()
 const $toast = useToast()
 
 const stopTransaction = (): void => {
+  if (props.connector.transactionId == null) {
+    $toast.error('No transaction to stop')
+    return
+  }
   uiClient
     .stopTransaction(props.hashId, props.connector.transactionId)
     .then(() => {
index 60e6c66564be7740fe521dfaade058e221071a82..faa8e9224ae883a3e61c719e38950cae5d2d57d1 100644 (file)
@@ -59,6 +59,13 @@ export class UIClient {
     })
   }
 
+  public async authorize (hashId: string, idTag: string): Promise<ResponsePayload> {
+    return this.sendRequest(ProcedureName.AUTHORIZE, {
+      hashIds: [hashId],
+      idTag,
+    })
+  }
+
   public async closeConnection (hashId: string): Promise<ResponsePayload> {
     return this.sendRequest(ProcedureName.CLOSE_CONNECTION, {
       hashIds: [hashId],
index 169a713e6357f509b5f217e436adda4e1e322ba0..1d8422abe79e6939f3e950690ab735dc94884725 100644 (file)
@@ -11,6 +11,7 @@ export enum AuthenticationType {
 
 export enum ProcedureName {
   ADD_CHARGING_STATIONS = 'addChargingStations',
+  AUTHORIZE = 'authorize',
   CLOSE_CONNECTION = 'closeConnection',
   DELETE_CHARGING_STATIONS = 'deleteChargingStations',
   LIST_CHARGING_STATIONS = 'listChargingStations',
@@ -35,6 +36,7 @@ export enum Protocol {
 export enum ProtocolVersion {
   '0.0.1' = '0.0.1',
 }
+
 export enum ResponseStatus {
   FAILURE = 'failure',
   SUCCESS = 'success',