fix: use nextTick to delay event emission
authorJérôme Benoit <jerome.benoit@sap.com>
Mon, 29 Jan 2024 16:34:53 +0000 (17:34 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Mon, 29 Jan 2024 16:34:53 +0000 (17:34 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/OCPPConstants.ts

index 12431266172c3d9c468c9fde322ff860991bfe00..f5bc60eaf0e52d628ae67f1c762a5788ed5f23d2 100644 (file)
@@ -2,6 +2,7 @@
 
 import { createWriteStream, readdirSync } from 'node:fs'
 import { dirname, join, resolve } from 'node:path'
+import { nextTick } from 'node:process'
 import { URL, fileURLToPath } from 'node:url'
 
 import type { ValidateFunction } from 'ajv'
@@ -437,6 +438,107 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
           })
       }
     )
+    this.on(
+      `Trigger${OCPP16MessageTrigger.BootNotification}`,
+      (chargingStation: ChargingStation) => {
+        chargingStation.ocppRequestService
+          .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
+          chargingStation,
+          OCPP16RequestCommand.BOOT_NOTIFICATION,
+          chargingStation.bootNotificationRequest,
+          { skipBufferingOnError: true, triggerMessage: true }
+        )
+          .then(response => {
+            chargingStation.bootNotificationResponse = response
+          })
+          .catch(error => {
+            logger.error(
+              `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger boot notification error:`,
+              error
+            )
+          })
+      }
+    )
+    this.on(`Trigger${OCPP16MessageTrigger.Heartbeat}`, (chargingStation: ChargingStation) => {
+      chargingStation.ocppRequestService
+        .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
+        chargingStation,
+        OCPP16RequestCommand.HEARTBEAT,
+        undefined,
+        {
+          triggerMessage: true
+        }
+      )
+        .catch(error => {
+          logger.error(
+            `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger heartbeat error:`,
+            error
+          )
+        })
+    })
+    this.on(
+      `$Trigger${OCPP16MessageTrigger.StatusNotification}`,
+      (chargingStation: ChargingStation, connectorId?: number) => {
+        const errorHandler = (error: Error): void => {
+          logger.error(
+            `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger status notification error:`,
+            error
+          )
+        }
+        if (connectorId != null) {
+          chargingStation.ocppRequestService
+            .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
+            chargingStation,
+            OCPP16RequestCommand.STATUS_NOTIFICATION,
+            {
+              connectorId,
+              errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+              status: chargingStation.getConnectorStatus(connectorId)?.status
+            },
+            {
+              triggerMessage: true
+            }
+          )
+            .catch(errorHandler)
+        } else if (chargingStation.hasEvses) {
+          for (const evseStatus of chargingStation.evses.values()) {
+            for (const [id, connectorStatus] of evseStatus.connectors) {
+              chargingStation.ocppRequestService
+                .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
+                chargingStation,
+                OCPP16RequestCommand.STATUS_NOTIFICATION,
+                {
+                  connectorId: id,
+                  errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                  status: connectorStatus.status
+                },
+                {
+                  triggerMessage: true
+                }
+              )
+                .catch(errorHandler)
+            }
+          }
+        } else {
+          for (const [id, connectorStatus] of chargingStation.connectors) {
+            chargingStation.ocppRequestService
+              .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
+              chargingStation,
+              OCPP16RequestCommand.STATUS_NOTIFICATION,
+              {
+                connectorId: id,
+                errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                status: connectorStatus.status
+              },
+              {
+                triggerMessage: true
+              }
+            )
+              .catch(errorHandler)
+          }
+        }
+      }
+    )
     this.validatePayload = this.validatePayload.bind(this)
   }
 
@@ -1044,11 +1146,13 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         idTag
       )
     }
-    this.emit(
-      OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-      chargingStation,
-      transactionConnectorId,
-      idTag
+    nextTick(() =>
+      this.emit(
+        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+        chargingStation,
+        transactionConnectorId,
+        idTag
+      )
     )
     return OCPP16Constants.OCPP_RESPONSE_ACCEPTED
   }
@@ -1451,95 +1555,21 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     try {
       switch (requestedMessage) {
         case OCPP16MessageTrigger.BootNotification:
-          setTimeout(() => {
-            chargingStation.ocppRequestService
-              .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
-              chargingStation,
-              OCPP16RequestCommand.BOOT_NOTIFICATION,
-              chargingStation.bootNotificationRequest,
-              { skipBufferingOnError: true, triggerMessage: true }
-            )
-              .then(response => {
-                chargingStation.bootNotificationResponse = response
-              })
-              .catch(Constants.EMPTY_FUNCTION)
-          }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY)
+          nextTick(() =>
+            this.emit(`Trigger${OCPP16MessageTrigger.BootNotification}`, chargingStation)
+          )
           return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
         case OCPP16MessageTrigger.Heartbeat:
-          setTimeout(() => {
-            chargingStation.ocppRequestService
-              .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
-              chargingStation,
-              OCPP16RequestCommand.HEARTBEAT,
-              undefined,
-              {
-                triggerMessage: true
-              }
-            )
-              .catch(Constants.EMPTY_FUNCTION)
-          }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY)
+          nextTick(() => this.emit(`Trigger${OCPP16MessageTrigger.Heartbeat}`, chargingStation))
           return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
         case OCPP16MessageTrigger.StatusNotification:
-          setTimeout(() => {
-            if (connectorId != null) {
-              chargingStation.ocppRequestService
-                .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
-                chargingStation,
-                OCPP16RequestCommand.STATUS_NOTIFICATION,
-                {
-                  connectorId,
-                  errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                  status: chargingStation.getConnectorStatus(connectorId)?.status
-                },
-                {
-                  triggerMessage: true
-                }
-              )
-                .catch(Constants.EMPTY_FUNCTION)
-            } else if (chargingStation.hasEvses) {
-              for (const evseStatus of chargingStation.evses.values()) {
-                for (const [id, connectorStatus] of evseStatus.connectors) {
-                  chargingStation.ocppRequestService
-                    .requestHandler<
-                  OCPP16StatusNotificationRequest,
-                  OCPP16StatusNotificationResponse
-                  >(
-                    chargingStation,
-                    OCPP16RequestCommand.STATUS_NOTIFICATION,
-                    {
-                      connectorId: id,
-                      errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                      status: connectorStatus.status
-                    },
-                    {
-                      triggerMessage: true
-                    }
-                  )
-                    .catch(Constants.EMPTY_FUNCTION)
-                }
-              }
-            } else {
-              for (const [id, connectorStatus] of chargingStation.connectors) {
-                chargingStation.ocppRequestService
-                  .requestHandler<
-                OCPP16StatusNotificationRequest,
-                OCPP16StatusNotificationResponse
-                >(
-                  chargingStation,
-                  OCPP16RequestCommand.STATUS_NOTIFICATION,
-                  {
-                    connectorId: id,
-                    errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                    status: connectorStatus.status
-                  },
-                  {
-                    triggerMessage: true
-                  }
-                )
-                  .catch(Constants.EMPTY_FUNCTION)
-              }
-            }
-          }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY)
+          nextTick(() =>
+            this.emit(
+              `Trigger${OCPP16MessageTrigger.StatusNotification}`,
+              chargingStation,
+              connectorId
+            )
+          )
           return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
         default:
           return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
index 40807c88e3bd51535207f21ead64f629bbd4b712..b036738719944fae935f62c03ec137c06acca761 100644 (file)
@@ -15,7 +15,6 @@ import { Constants } from '../../utils/index.js'
 // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 export class OCPPConstants {
   static readonly OCPP_WEBSOCKET_TIMEOUT = 60000 // Ms
-  static readonly OCPP_TRIGGER_MESSAGE_DELAY = 500 // Ms
 
   static readonly OCPP_MEASURANDS_SUPPORTED = Object.freeze([
     MeterValueMeasurand.STATE_OF_CHARGE,