Implement firmwareUpgrade CS template section support
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 11 Jan 2023 18:57:39 +0000 (19:57 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 11 Jan 2023 18:57:39 +0000 (19:57 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/assets/station-templates/chargex.station-template.json
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/types/ChargingStationTemplate.ts

index 7c20df31ed97d7ecd4f9b45b7a6a55a7b4d07cc2..3f4a6be13e18147202b2a63968817b3c1025f349 100644 (file)
   "voltageOut": 230,
   "beginEndMeterValues": true,
   "outOfOrderEndMeterValues": true,
+  "firmwareUpgrade": {
+    "versionUpgrade": {
+      "patternGroup": 3
+    }
+  },
   "commandsSupport": {
     "incomingCommands": {
       "Reset": true,
index 7e324b257df0a7cc69b1050e91ed03ed9e4d1eff..a7a41dddcbf6dbf30a4487c0f925e54dfc1f8b25 100644 (file)
@@ -6,6 +6,7 @@ import path from 'path';
 import { URL } from 'url';
 import { parentPort } from 'worker_threads';
 
+import merge from 'just-merge';
 import WebSocket, { type RawData } from 'ws';
 
 import BaseError from '../exception/BaseError';
@@ -18,6 +19,7 @@ import type { ChargingStationOcppConfiguration } from '../types/ChargingStationO
 import {
   type ChargingStationTemplate,
   CurrentType,
+  type FirmwareUpgrade,
   PowerUnits,
   type WsOptions,
 } from '../types/ChargingStationTemplate';
@@ -563,6 +565,15 @@ export default class ChargingStation {
     }
   }
 
+  public getFirmwareUpgrade(): FirmwareUpgrade {
+    return merge(
+      {
+        reset: true,
+      },
+      this.stationInfo.firmwareUpgrade
+    );
+  }
+
   public async reset(reason?: StopTransactionReason): Promise<void> {
     await this.stop(reason);
     await Utils.sleep(this.stationInfo.resetTime);
@@ -1002,11 +1013,17 @@ export default class ChargingStation {
       this.stationInfo.firmwareVersion &&
       this.stationInfo.firmwareVersionPattern
     ) {
+      const versionStep = this.getFirmwareUpgrade()?.versionUpgrade?.step ?? 1;
+      const patternGroup: number =
+        this.getFirmwareUpgrade()?.versionUpgrade?.patternGroup ??
+        this.stationInfo.firmwareVersion.split('.').length;
       const match = this.stationInfo.firmwareVersion
         .match(new RegExp(this.stationInfo.firmwareVersionPattern))
-        .slice(1, this.stationInfo.firmwareVersion.split('.').length + 1);
+        .slice(1, patternGroup + 1);
       const patchLevelIndex = match.length - 1;
-      match[patchLevelIndex] = (Utils.convertToInt(match[patchLevelIndex]) + 1).toString();
+      match[patchLevelIndex] = (
+        Utils.convertToInt(match[patchLevelIndex]) + versionStep
+      ).toString();
       this.stationInfo.firmwareVersion = match.join('.');
     }
   }
index 3f1b2cfee0b30ee1684d06288949ae6155506371..b80a8f4bf65d10048d7fe39e4823e52efcb85ec4 100644 (file)
@@ -944,6 +944,18 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         OCPP16IncomingRequestCommand.UPDATE_FIRMWARE
       ) === false
     ) {
+      logger.warn(
+        `${chargingStation.logPrefix()} Cannot simulate firmware update: feature profile not supported`
+      );
+      return OCPPConstants.OCPP_RESPONSE_EMPTY;
+    }
+    if (
+      !Utils.isNullOrUndefined(chargingStation.stationInfo.firmwareStatus) &&
+      chargingStation.stationInfo.firmwareStatus !== OCPP16FirmwareStatus.Installed
+    ) {
+      logger.warn(
+        `${chargingStation.logPrefix()} Cannot simulate firmware update: firmware update is already in progress`
+      );
       return OCPPConstants.OCPP_RESPONSE_EMPTY;
     }
     const retrieveDate = Utils.convertToDate(commandPayload.retrieveDate);
@@ -993,6 +1005,18 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           OCPP16ChargePointStatus.UNAVAILABLE;
       }
     }
+    if (
+      chargingStation.getFirmwareUpgrade()?.failureStatus &&
+      !Utils.isEmptyString(chargingStation.getFirmwareUpgrade().failureStatus)
+    ) {
+      await chargingStation.ocppRequestService.requestHandler<
+        OCPP16FirmwareStatusNotificationRequest,
+        OCPP16FirmwareStatusNotificationResponse
+      >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+        status: chargingStation.getFirmwareUpgrade().failureStatus,
+      });
+      return;
+    }
     await chargingStation.ocppRequestService.requestHandler<
       OCPP16FirmwareStatusNotificationRequest,
       OCPP16FirmwareStatusNotificationResponse
@@ -1016,8 +1040,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       status: OCPP16FirmwareStatus.Installing,
     });
     chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Installing;
-    await Utils.sleep(Utils.getRandomInteger(minDelay, maxDelay) * 1000);
-    await chargingStation.reset(OCPP16StopTransactionReason.REBOOT);
+    if (chargingStation.getFirmwareUpgrade().reset === true) {
+      await Utils.sleep(Utils.getRandomInteger(minDelay, maxDelay) * 1000);
+      await chargingStation.reset(OCPP16StopTransactionReason.REBOOT);
+    }
   }
 
   private async handleRequestGetDiagnostics(
index c6640771e673933d1d67ac252801ff22fbd9a638..99b43765232fde1a66428745d7b411b5d0af89f7 100644 (file)
@@ -40,14 +40,13 @@ export enum Voltage {
 
 export type WsOptions = ClientOptions & ClientRequestArgs;
 
-type FirmwareUpgrade = {
+export type FirmwareUpgrade = {
   versionUpgrade: {
-    patternGroup?: number | number[];
+    patternGroup?: number;
     step?: number;
   };
   reset?: boolean;
-  resetDelay?: number;
-  failureMessage?: FirmwareStatus;
+  failureStatus?: FirmwareStatus;
 };
 
 type CommandsSupport = {