feat: add events for charging station status change
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 10 Nov 2023 12:39:41 +0000 (13:39 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 10 Nov 2023 12:39:41 +0000 (13:39 +0100)
closes #458

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/types/ChargingStation.ts [new file with mode: 0644]
src/types/ChargingStationWorker.ts
src/types/index.ts

index 441c5d1e95652a8d7cfc67174cf1b2834848cea5..575293e8aa4ee6992e2fcac6bc2b087ec19ac04c 100644 (file)
@@ -1,6 +1,7 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
 import { createHash } from 'node:crypto';
+import { EventEmitter } from 'node:events';
 import { type FSWatcher, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
 import { dirname, join } from 'node:path';
 import { URL } from 'node:url';
@@ -67,6 +68,7 @@ import {
   type BootNotificationResponse,
   type CachedRequest,
   type ChargingStationConfiguration,
+  ChargingStationEvents,
   type ChargingStationInfo,
   type ChargingStationOcppConfiguration,
   type ChargingStationTemplate,
@@ -152,7 +154,7 @@ import {
   // watchJsonFile,
 } from '../utils';
 
-export class ChargingStation {
+export class ChargingStation extends EventEmitter {
   public readonly index: number;
   public readonly templateFile: string;
   public stationInfo!: ChargingStationInfo;
@@ -190,6 +192,7 @@ export class ChargingStation {
   private reservationExpirationSetInterval?: NodeJS.Timeout;
 
   constructor(index: number, templateFile: string) {
+    super();
     this.started = false;
     this.starting = false;
     this.stopping = false;
@@ -206,6 +209,16 @@ export class ChargingStation {
     this.idTagsCache = IdTagsCache.getInstance();
     this.chargingStationWorkerBroadcastChannel = new ChargingStationWorkerBroadcastChannel(this);
 
+    this.on(ChargingStationEvents.started, () => {
+      parentPort?.postMessage(buildStartedMessage(this));
+    });
+    this.on(ChargingStationEvents.stopped, () => {
+      parentPort?.postMessage(buildStoppedMessage(this));
+    });
+    this.on(ChargingStationEvents.updated, () => {
+      parentPort?.postMessage(buildUpdatedMessage(this));
+    });
+
     this.initialize();
   }
 
@@ -714,7 +727,7 @@ export class ChargingStation {
         //   },
         // );
         this.started = true;
-        parentPort?.postMessage(buildStartedMessage(this));
+        this.emit(ChargingStationEvents.started);
         this.starting = false;
       } else {
         logger.warn(`${this.logPrefix()} Charging station is already starting...`);
@@ -742,7 +755,7 @@ export class ChargingStation {
         delete this.bootNotificationResponse;
         this.started = false;
         this.saveConfiguration();
-        parentPort?.postMessage(buildStoppedMessage(this));
+        this.emit(ChargingStationEvents.stopped);
         this.stopping = false;
       } else {
         logger.warn(`${this.logPrefix()} Charging station is already stopping...`);
@@ -881,7 +894,7 @@ export class ChargingStation {
       this.automaticTransactionGenerator?.start();
     }
     this.saveAutomaticTransactionGeneratorConfiguration();
-    parentPort?.postMessage(buildUpdatedMessage(this));
+    this.emit(ChargingStationEvents.updated);
   }
 
   public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
@@ -893,7 +906,7 @@ export class ChargingStation {
       this.automaticTransactionGenerator?.stop();
     }
     this.saveAutomaticTransactionGeneratorConfiguration();
-    parentPort?.postMessage(buildUpdatedMessage(this));
+    this.emit(ChargingStationEvents.updated);
   }
 
   public async stopTransactionOnConnector(
@@ -1803,7 +1816,9 @@ export class ChargingStation {
         );
       }
       if (this.isRegistered() === true) {
+        this.emit(ChargingStationEvents.registered);
         if (this.inAcceptedState() === true) {
+          this.emit(ChargingStationEvents.accepted);
           await this.startMessageSequence();
         }
       } else {
@@ -1813,7 +1828,7 @@ export class ChargingStation {
       }
       this.wsConnectionRestarted = false;
       this.autoReconnectRetryCount = 0;
-      parentPort?.postMessage(buildUpdatedMessage(this));
+      this.emit(ChargingStationEvents.updated);
     } else {
       logger.warn(
         `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.toString()} failed`,
@@ -1843,7 +1858,7 @@ export class ChargingStation {
         this.started === true && (await this.reconnect());
         break;
     }
-    parentPort?.postMessage(buildUpdatedMessage(this));
+    this.emit(ChargingStationEvents.updated);
   }
 
   private getCachedRequest(messageType: MessageType, messageId: string): CachedRequest | undefined {
@@ -1954,7 +1969,7 @@ export class ChargingStation {
             logger.error(`${this.logPrefix()} ${errorMsg}`);
             throw new OCPPError(ErrorType.PROTOCOL_ERROR, errorMsg);
         }
-        parentPort?.postMessage(buildUpdatedMessage(this));
+        this.emit(ChargingStationEvents.updated);
       } else {
         throw new OCPPError(
           ErrorType.PROTOCOL_ERROR,
index 03bf136720ef590d3bfc4d74934b4ea420ce9754..e978b24fdfee0fcab7a0323383ec87f2f0e595ec 100644 (file)
@@ -1,7 +1,5 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
-import { parentPort } from 'node:worker_threads';
-
 import type { JSONSchemaType } from 'ajv';
 import { secondsToMilliseconds } from 'date-fns';
 
@@ -16,6 +14,7 @@ import {
 import { OCPPError } from '../../../exception';
 import {
   type ChangeConfigurationResponse,
+  ChargingStationEvents,
   type ClearChargingProfileResponse,
   ErrorType,
   type GenericResponse,
@@ -53,13 +52,7 @@ import {
   type SetChargingProfileResponse,
   type UnlockConnectorResponse,
 } from '../../../types';
-import {
-  Constants,
-  buildUpdatedMessage,
-  convertToInt,
-  isNullOrUndefined,
-  logger,
-} from '../../../utils';
+import { Constants, convertToInt, isNullOrUndefined, logger } from '../../../utils';
 import { OCPPResponseService } from '../OCPPResponseService';
 
 const moduleName = 'OCPP16ResponseService';
@@ -700,7 +693,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
         OCPP16ChargePointStatus.Available,
       );
     }
-    parentPort?.postMessage(buildUpdatedMessage(chargingStation));
+    chargingStation.emit(ChargingStationEvents.updated);
   }
 
   private async handleResponseStopTransaction(
@@ -757,7 +750,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     }
     resetConnectorStatus(chargingStation.getConnectorStatus(transactionConnectorId!)!);
     chargingStation.stopMeterValues(transactionConnectorId!);
-    parentPort?.postMessage(buildUpdatedMessage(chargingStation));
+    chargingStation.emit(ChargingStationEvents.updated);
     const logMsg = `${chargingStation.logPrefix()} Transaction with id ${
       requestPayload.transactionId
     } STOPPED on ${
diff --git a/src/types/ChargingStation.ts b/src/types/ChargingStation.ts
new file mode 100644 (file)
index 0000000..cdd3a5e
--- /dev/null
@@ -0,0 +1,7 @@
+export enum ChargingStationEvents {
+  started = 'started',
+  stopped = 'stopped',
+  registered = 'registered',
+  accepted = 'accepted',
+  updated = 'updated',
+}
index 2326d765c7ddd05f3021cb46d1d001ae2f4da0b9..5e56d4fd0e088fbc13deeb5e9fec08842bd7ba2a 100644 (file)
@@ -1,6 +1,7 @@
 import type { WebSocket } from 'ws';
 
 import type { ChargingStationAutomaticTransactionGeneratorConfiguration } from './AutomaticTransactionGenerator';
+import { ChargingStationEvents } from './ChargingStation';
 import type { ChargingStationInfo } from './ChargingStationInfo';
 import type { ChargingStationOcppConfiguration } from './ChargingStationOcppConfiguration';
 import type { ConnectorStatus } from './ConnectorStatus';
@@ -40,17 +41,18 @@ export interface ChargingStationData extends WorkerData {
 }
 
 enum ChargingStationMessageEvents {
-  started = 'started',
-  stopped = 'stopped',
-  updated = 'updated',
   performanceStatistics = 'performanceStatistics',
 }
 
 export const ChargingStationWorkerMessageEvents = {
   ...WorkerMessageEvents,
+  ...ChargingStationEvents,
   ...ChargingStationMessageEvents,
 } as const;
-export type ChargingStationWorkerMessageEvents = WorkerMessageEvents | ChargingStationMessageEvents;
+export type ChargingStationWorkerMessageEvents =
+  | WorkerMessageEvents
+  | ChargingStationEvents
+  | ChargingStationMessageEvents;
 
 export type ChargingStationWorkerMessageData = ChargingStationData | Statistics;
 
index 66a9682277abb2a637afa4c07f92a282232a12c3..2cc76b1f08ee562dd4c818e92a03ad50b6ea5503 100644 (file)
@@ -262,3 +262,4 @@ export {
   type ReservationKey,
   ReservationTerminationReason,
 } from './ocpp/Reservation';
+export { ChargingStationEvents } from './ChargingStation';