Add initial support for OCPP 1.6 firmware update simulation
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 8 Jan 2023 23:09:05 +0000 (00:09 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 8 Jan 2023 23:09:05 +0000 (00:09 +0100)
Reference #169 and #36

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
15 files changed:
README.md
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ui-server/ui-services/AbstractUIService.ts
src/types/ChargingStationInfo.ts
src/types/UIProtocol.ts
src/types/WorkerBroadcastChannel.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/1.6/Responses.ts
src/types/ocpp/Requests.ts
src/types/ocpp/Responses.ts
test/robohydra/messages.txt

index 131a263c378b0d775527a1143a2106407fba5094..f1509c61352910e52005aed60015be0d395befeb 100644 (file)
--- a/README.md
+++ b/README.md
@@ -328,8 +328,8 @@ make SUBMODULES_INIT=true
 
 - :white_check_mark: GetDiagnostics
 - :white_check_mark: DiagnosticsStatusNotification
-- :x: FirmwareStatusNotification
-- :x: UpdateFirmware
+- :white_check_mark: FirmwareStatusNotification
+- :white_check_mark: UpdateFirmware
 
 #### Local Auth List Management Profile
 
index 587ca02ff143d391c222b07ca11a9f81fdf7cb70..806bcd752cd50a2cfdc8408e8b9147e48fcaa81a 100644 (file)
@@ -43,6 +43,8 @@ import {
   type BootNotificationRequest,
   type CachedRequest,
   type ErrorCallback,
+  FirmwareStatus,
+  type FirmwareStatusNotificationRequest,
   type HeartbeatRequest,
   type IncomingRequest,
   IncomingRequestCommand,
@@ -54,6 +56,7 @@ import {
 import {
   type BootNotificationResponse,
   type ErrorResponse,
+  type FirmwareStatusNotificationResponse,
   type HeartbeatResponse,
   type MeterValuesResponse,
   RegistrationStatusEnumType,
@@ -1837,6 +1840,16 @@ export default class ChargingStation {
       });
       this.getConnectorStatus(connectorId).status = chargePointStatus;
     }
+    if (this.stationInfo?.firmwareStatus === FirmwareStatus.Installing) {
+      await this.ocppRequestService.requestHandler<
+        FirmwareStatusNotificationRequest,
+        FirmwareStatusNotificationResponse
+      >(this, RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+        status: FirmwareStatus.Installed,
+      });
+      this.stationInfo.firmwareStatus = FirmwareStatus.Installed;
+      // TODO: bump firmware version
+    }
     // Start the ATG
     if (this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true) {
       this.startAutomaticTransactionGenerator();
index 7c9883bd4277995e3abce9386327583b4479d09e..1528d65c0983580e86fb99b7e0b0f314612dd7a7 100644 (file)
@@ -4,6 +4,8 @@ import { StandardParametersKey } from '../types/ocpp/Configuration';
 import {
   type BootNotificationRequest,
   type DataTransferRequest,
+  type DiagnosticsStatusNotificationRequest,
+  type FirmwareStatusNotificationRequest,
   type HeartbeatRequest,
   type MeterValuesRequest,
   RequestCommand,
@@ -13,6 +15,8 @@ import {
   type BootNotificationResponse,
   type DataTransferResponse,
   DataTransferStatus,
+  type DiagnosticsStatusNotificationResponse,
+  type FirmwareStatusNotificationResponse,
   type HeartbeatResponse,
   type MeterValuesResponse,
   RegistrationStatusEnumType,
@@ -53,7 +57,9 @@ type CommandResponse =
   | StatusNotificationResponse
   | HeartbeatResponse
   | MeterValuesResponse
-  | DataTransferResponse;
+  | DataTransferResponse
+  | DiagnosticsStatusNotificationResponse
+  | FirmwareStatusNotificationResponse;
 
 type CommandHandler = (
   requestPayload?: BroadcastChannelRequestPayload
@@ -190,6 +196,22 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
             DataTransferResponse
           >(this.chargingStation, RequestCommand.DATA_TRANSFER, requestPayload),
       ],
+      [
+        BroadcastChannelProcedureName.DIAGNOSTICS_STATUS_NOTIFICATION,
+        async (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.ocppRequestService.requestHandler<
+            DiagnosticsStatusNotificationRequest,
+            DiagnosticsStatusNotificationResponse
+          >(this.chargingStation, RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, requestPayload),
+      ],
+      [
+        BroadcastChannelProcedureName.FIRMWARE_STATUS_NOTIFICATION,
+        async (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.ocppRequestService.requestHandler<
+            FirmwareStatusNotificationRequest,
+            FirmwareStatusNotificationResponse
+          >(this.chargingStation, RequestCommand.FIRMWARE_STATUS_NOTIFICATION, requestPayload),
+      ],
     ]);
     this.chargingStation = chargingStation;
     this.onmessage = this.requestHandler.bind(this) as (message: MessageEvent) => void;
@@ -221,7 +243,11 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
     let commandResponse: CommandResponse | void;
     try {
       commandResponse = await this.commandHandler(command, requestPayload);
-      if (commandResponse === undefined || commandResponse === null) {
+      if (
+        commandResponse === undefined ||
+        commandResponse === null ||
+        Utils.isEmptyObject(commandResponse as CommandResponse)
+      ) {
         responsePayload = {
           hashId: this.chargingStation.stationInfo.hashId,
           status: ResponseStatus.SUCCESS,
index 8b19902eb609ea7594ff471e22aaf95b00910d80..a170e3058eea1d11966a3bf4683ce6a8fed14b96 100644 (file)
@@ -25,7 +25,6 @@ import {
   type ChangeAvailabilityRequest,
   type ChangeConfigurationRequest,
   type ClearChargingProfileRequest,
-  type DiagnosticsStatusNotificationRequest,
   type GetConfigurationRequest,
   type GetDiagnosticsRequest,
   OCPP16AvailabilityType,
@@ -33,6 +32,9 @@ import {
   type OCPP16ClearCacheRequest,
   type OCPP16DataTransferRequest,
   OCPP16DataTransferVendorId,
+  type OCPP16DiagnosticsStatusNotificationRequest,
+  OCPP16FirmwareStatus,
+  type OCPP16FirmwareStatusNotificationRequest,
   type OCPP16HeartbeatRequest,
   OCPP16IncomingRequestCommand,
   OCPP16MessageTrigger,
@@ -50,12 +52,13 @@ import {
   type ChangeAvailabilityResponse,
   type ChangeConfigurationResponse,
   type ClearChargingProfileResponse,
-  type DiagnosticsStatusNotificationResponse,
   type GetConfigurationResponse,
   type GetDiagnosticsResponse,
   type OCPP16BootNotificationResponse,
   type OCPP16DataTransferResponse,
   OCPP16DataTransferStatus,
+  type OCPP16DiagnosticsStatusNotificationResponse,
+  type OCPP16FirmwareStatusNotificationResponse,
   type OCPP16HeartbeatResponse,
   type OCPP16StatusNotificationResponse,
   type OCPP16TriggerMessageResponse,
@@ -132,7 +135,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
       [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
       [OCPP16IncomingRequestCommand.DATA_TRANSFER, this.handleRequestDataTransfer.bind(this)],
-      // [OCPP16IncomingRequestCommand.UPDATE_FIRMWARE, this.handleRequestUpdateFirmware.bind(this)],
+      [OCPP16IncomingRequestCommand.UPDATE_FIRMWARE, this.handleRequestUpdateFirmware.bind(this)],
     ]);
     this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>([
       [
@@ -1036,13 +1039,76 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ) {
       return OCPPConstants.OCPP_RESPONSE_EMPTY;
     }
-    logger.debug(
-      chargingStation.logPrefix() +
-        ' ' +
-        OCPP16IncomingRequestCommand.UPDATE_FIRMWARE +
-        ' request received: %j',
-      commandPayload
-    );
+    const retrieveDate = Utils.convertToDate(commandPayload.retrieveDate);
+    if (retrieveDate.getTime() <= Date.now()) {
+      this.asyncResource
+        .runInAsyncScope(
+          this.updateFirmware.bind(this) as (
+            this: OCPP16IncomingRequestService,
+            ...args: any[]
+          ) => Promise<void>,
+          this,
+          chargingStation
+        )
+        .catch(() => {
+          /* This is intentional */
+        });
+    } else {
+      setTimeout(() => {
+        this.updateFirmware(chargingStation).catch(() => {
+          /* Intentional */
+        });
+      }, retrieveDate.getTime() - Date.now());
+    }
+    return OCPPConstants.OCPP_RESPONSE_EMPTY;
+  }
+
+  private async updateFirmware(
+    chargingStation: ChargingStation,
+    minDelay = 15,
+    maxDelay = 30
+  ): Promise<void> {
+    chargingStation.stopAutomaticTransactionGenerator();
+    for (const connectorId of chargingStation.connectors.keys()) {
+      if (
+        connectorId > 0 &&
+        chargingStation.getConnectorStatus(connectorId).transactionStarted === false
+      ) {
+        await chargingStation.ocppRequestService.requestHandler<
+          OCPP16StatusNotificationRequest,
+          OCPP16StatusNotificationResponse
+        >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
+          connectorId,
+          status: OCPP16ChargePointStatus.UNAVAILABLE,
+          errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+        });
+      }
+    }
+    await chargingStation.ocppRequestService.requestHandler<
+      OCPP16FirmwareStatusNotificationRequest,
+      OCPP16FirmwareStatusNotificationResponse
+    >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+      status: OCPP16FirmwareStatus.Downloading,
+    });
+    chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Downloading;
+    await Utils.sleep(Utils.getRandomInteger(minDelay, maxDelay) * 1000);
+    await chargingStation.ocppRequestService.requestHandler<
+      OCPP16FirmwareStatusNotificationRequest,
+      OCPP16FirmwareStatusNotificationResponse
+    >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+      status: OCPP16FirmwareStatus.Downloaded,
+    });
+    chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Downloaded;
+    await Utils.sleep(Utils.getRandomInteger(minDelay, maxDelay) * 1000);
+    await chargingStation.ocppRequestService.requestHandler<
+      OCPP16FirmwareStatusNotificationRequest,
+      OCPP16FirmwareStatusNotificationResponse
+    >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
+      status: OCPP16FirmwareStatus.Installing,
+    });
+    chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Installing;
+    await Utils.sleep(Utils.getRandomInteger(minDelay, maxDelay) * 1000);
+    await chargingStation.reset();
   }
 
   private async handleRequestGetDiagnostics(
@@ -1058,13 +1124,6 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ) {
       return OCPPConstants.OCPP_RESPONSE_EMPTY;
     }
-    logger.debug(
-      chargingStation.logPrefix() +
-        ' ' +
-        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS +
-        ' request received: %j',
-      commandPayload
-    );
     const uri = new URL(commandPayload.location);
     if (uri.protocol.startsWith('ftp:')) {
       let ftpClient: Client;
@@ -1092,8 +1151,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
               } bytes transferred from diagnostics archive ${info.name}`
             );
             await chargingStation.ocppRequestService.requestHandler<
-              DiagnosticsStatusNotificationRequest,
-              DiagnosticsStatusNotificationResponse
+              OCPP16DiagnosticsStatusNotificationRequest,
+              OCPP16DiagnosticsStatusNotificationResponse
             >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
               status: OCPP16DiagnosticsStatus.Uploading,
             });
@@ -1107,8 +1166,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           );
           if (uploadResponse.code === 226) {
             await chargingStation.ocppRequestService.requestHandler<
-              DiagnosticsStatusNotificationRequest,
-              DiagnosticsStatusNotificationResponse
+              OCPP16DiagnosticsStatusNotificationRequest,
+              OCPP16DiagnosticsStatusNotificationResponse
             >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
               status: OCPP16DiagnosticsStatus.Uploaded,
             });
@@ -1134,8 +1193,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         );
       } catch (error) {
         await chargingStation.ocppRequestService.requestHandler<
-          DiagnosticsStatusNotificationRequest,
-          DiagnosticsStatusNotificationResponse
+          OCPP16DiagnosticsStatusNotificationRequest,
+          OCPP16DiagnosticsStatusNotificationResponse
         >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
           status: OCPP16DiagnosticsStatus.UploadFailed,
         });
@@ -1156,8 +1215,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         } to transfer the diagnostic logs archive`
       );
       await chargingStation.ocppRequestService.requestHandler<
-        DiagnosticsStatusNotificationRequest,
-        DiagnosticsStatusNotificationResponse
+        OCPP16DiagnosticsStatusNotificationRequest,
+        OCPP16DiagnosticsStatusNotificationResponse
       >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
         status: OCPP16DiagnosticsStatus.UploadFailed,
       });
index 955dd08510add96008d3d87bf5f0fa25922cb132..3c72faf223eea8f8dca3adf78327cc7d432a7126 100644 (file)
@@ -10,12 +10,13 @@ import OCPPError from '../../../exception/OCPPError';
 import type { JsonObject, JsonType } from '../../../types/JsonType';
 import type { OCPP16MeterValuesRequest } from '../../../types/ocpp/1.6/MeterValues';
 import {
-  type DiagnosticsStatusNotificationRequest,
   type OCPP16BootNotificationRequest,
   type OCPP16DataTransferRequest,
+  type OCPP16DiagnosticsStatusNotificationRequest,
   type OCPP16HeartbeatRequest,
   OCPP16RequestCommand,
   type OCPP16StatusNotificationRequest,
+  type OCPP16UpdateFirmwareRequest,
 } from '../../../types/ocpp/1.6/Requests';
 import type {
   OCPP16AuthorizeRequest,
@@ -77,7 +78,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
             ),
             'utf8'
           )
-        ) as JSONSchemaType<DiagnosticsStatusNotificationRequest>,
+        ) as JSONSchemaType<OCPP16DiagnosticsStatusNotificationRequest>,
       ],
       [
         OCPP16RequestCommand.HEARTBEAT,
@@ -151,6 +152,18 @@ export default class OCPP16RequestService extends OCPPRequestService {
           )
         ) as JSONSchemaType<OCPP16DataTransferRequest>,
       ],
+      [
+        OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16UpdateFirmwareRequest>,
+      ],
     ]);
     this.buildRequestPayload.bind(this);
   }
@@ -223,7 +236,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
         } as unknown as Request;
       case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
         return {
-          status: commandParams?.diagnosticsStatus,
+          status: commandParams?.status,
         } as unknown as Request;
       case OCPP16RequestCommand.HEARTBEAT:
         return {} as unknown as Request;
@@ -281,6 +294,10 @@ export default class OCPP16RequestService extends OCPPRequestService {
         } as unknown as Request;
       case OCPP16RequestCommand.DATA_TRANSFER:
         return commandParams as unknown as Request;
+      case OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION:
+        return {
+          status: commandParams?.status,
+        } as unknown as Request;
       default:
         // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
         throw new OCPPError(
index e29957be3fdacebd525abc872cf9f5a466c22cee..ac183aecc4e9898d82c3e0c2defa2d775095859a 100644 (file)
@@ -25,11 +25,12 @@ import type {
   ChangeAvailabilityResponse,
   ChangeConfigurationResponse,
   ClearChargingProfileResponse,
-  DiagnosticsStatusNotificationResponse,
   GetConfigurationResponse,
   GetDiagnosticsResponse,
   OCPP16BootNotificationResponse,
   OCPP16DataTransferResponse,
+  OCPP16DiagnosticsStatusNotificationResponse,
+  OCPP16FirmwareStatusNotificationResponse,
   OCPP16HeartbeatResponse,
   OCPP16StatusNotificationResponse,
   OCPP16TriggerMessageResponse,
@@ -87,6 +88,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       [OCPP16RequestCommand.METER_VALUES, this.emptyResponseHandler.bind(this)],
       [OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
       [OCPP16RequestCommand.DATA_TRANSFER, this.emptyResponseHandler.bind(this)],
+      [OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
     ]);
     this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>([
       [
@@ -183,7 +185,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
             ),
             'utf8'
           )
-        ) as JSONSchemaType<DiagnosticsStatusNotificationResponse>,
+        ) as JSONSchemaType<OCPP16DiagnosticsStatusNotificationResponse>,
       ],
       [
         OCPP16RequestCommand.DATA_TRANSFER,
@@ -197,6 +199,18 @@ export default class OCPP16ResponseService extends OCPPResponseService {
           )
         ) as JSONSchemaType<OCPP16DataTransferResponse>,
       ],
+      [
+        OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
+        JSON.parse(
+          fs.readFileSync(
+            path.resolve(
+              path.dirname(fileURLToPath(import.meta.url)),
+              '../../../assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json'
+            ),
+            'utf8'
+          )
+        ) as JSONSchemaType<OCPP16FirmwareStatusNotificationResponse>,
+      ],
     ]);
     this.jsonIncomingRequestResponseSchemas = new Map([
       [
index 1d270b38c6c1d5264d90a369a8ed8a74d799968f..5a418b9d4baf53cc3032efee92e808971da58626 100644 (file)
@@ -44,6 +44,10 @@ export default abstract class AbstractUIService {
     [ProcedureName.HEARTBEAT]: BroadcastChannelProcedureName.HEARTBEAT,
     [ProcedureName.METER_VALUES]: BroadcastChannelProcedureName.METER_VALUES,
     [ProcedureName.DATA_TRANSFER]: BroadcastChannelProcedureName.DATA_TRANSFER,
+    [ProcedureName.DIAGNOSTICS_STATUS_NOTIFICATION]:
+      BroadcastChannelProcedureName.DIAGNOSTICS_STATUS_NOTIFICATION,
+    [ProcedureName.FIRMWARE_STATUS_NOTIFICATION]:
+      BroadcastChannelProcedureName.FIRMWARE_STATUS_NOTIFICATION,
   };
 
   protected readonly requestHandlers: Map<ProcedureName, ProtocolRequestHandler>;
index 6509887030e2640cd4a1576cd6472e37a193201a..29ff6fb719b6f550d600a5275e7d5ff99cb4be9a 100644 (file)
@@ -1,4 +1,5 @@
 import type { ChargingStationTemplate } from './ChargingStationTemplate';
+import type { FirmwareStatus } from './ocpp/Requests';
 
 export type ChargingStationInfo = Omit<
   ChargingStationTemplate,
@@ -18,6 +19,7 @@ export type ChargingStationInfo = Omit<
   meterSerialNumber?: string;
   maximumPower?: number; // Always in Watt
   maximumAmperage?: number; // Always in Ampere
+  firmwareStatus?: FirmwareStatus;
 };
 
 export type ChargingStationInfoConfiguration = {
index 8c9379b4570b6a5e6a7ddb643a51d5007e3a46b6..3b6592a5765a480965c62e645e210ca870703176 100644 (file)
@@ -45,6 +45,8 @@ export enum ProcedureName {
   HEARTBEAT = 'heartbeat',
   METER_VALUES = 'meterValues',
   DATA_TRANSFER = 'dataTransfer',
+  DIAGNOSTICS_STATUS_NOTIFICATION = 'diagnosticsStatusNotification',
+  FIRMWARE_STATUS_NOTIFICATION = 'firmwareStatusNotification',
 }
 
 export interface RequestPayload extends JsonObject {
index b7b8580d134e87965c46a69a64bc7c6b02d53a27..2c174cd5fae6f594f38e1dfc60d82952d99a331d 100644 (file)
@@ -22,6 +22,8 @@ export enum BroadcastChannelProcedureName {
   HEARTBEAT = 'heartbeat',
   METER_VALUES = 'meterValues',
   DATA_TRANSFER = 'dataTransfer',
+  DIAGNOSTICS_STATUS_NOTIFICATION = 'diagnosticsStatusNotification',
+  FIRMWARE_STATUS_NOTIFICATION = 'firmwareStatusNotification',
 }
 
 export interface BroadcastChannelRequestPayload extends RequestPayload {
index 678eacc990e50012964a66611eac978ed0d8c55c..47b110ab4dae1e0d5076f058de63784c424ea86f 100644 (file)
@@ -135,7 +135,7 @@ export enum OCPP16FirmwareStatus {
 
 export type OCPP16FirmwareStatusNotificationRequest = {
   status: OCPP16FirmwareStatus;
-};
+} & JsonObject;
 
 export interface GetDiagnosticsRequest extends JsonObject {
   location: string;
@@ -145,7 +145,7 @@ export interface GetDiagnosticsRequest extends JsonObject {
   stopTime?: Date;
 }
 
-export interface DiagnosticsStatusNotificationRequest extends JsonObject {
+export interface OCPP16DiagnosticsStatusNotificationRequest extends JsonObject {
   status: OCPP16DiagnosticsStatus;
 }
 
index 1ccd78e2fa0acbf39b8b586999675dbcc1fc0585..84648e47e5d90b4ffd83d3def6f831098802b084 100644 (file)
@@ -72,11 +72,13 @@ export interface ClearChargingProfileResponse extends JsonObject {
 
 export type OCPP16UpdateFirmwareResponse = EmptyObject;
 
+export type OCPP16FirmwareStatusNotificationResponse = EmptyObject;
+
 export interface GetDiagnosticsResponse extends JsonObject {
   fileName?: string;
 }
 
-export type DiagnosticsStatusNotificationResponse = EmptyObject;
+export type OCPP16DiagnosticsStatusNotificationResponse = EmptyObject;
 
 export enum OCPP16TriggerMessageStatus {
   ACCEPTED = 'Accepted',
index a21949962049f95634c73d5fb061a7694748ead0..884da269e5e863c30082c6a04a22bb35653d0778 100644 (file)
@@ -7,7 +7,9 @@ import {
   OCPP16AvailabilityType,
   type OCPP16BootNotificationRequest,
   type OCPP16DataTransferRequest,
+  type OCPP16DiagnosticsStatusNotificationRequest,
   OCPP16FirmwareStatus,
+  type OCPP16FirmwareStatusNotificationRequest,
   type OCPP16HeartbeatRequest,
   OCPP16IncomingRequestCommand,
   OCPP16MessageTrigger,
@@ -68,6 +70,10 @@ export type MeterValuesRequest = OCPP16MeterValuesRequest;
 
 export type DataTransferRequest = OCPP16DataTransferRequest;
 
+export type DiagnosticsStatusNotificationRequest = OCPP16DiagnosticsStatusNotificationRequest;
+
+export type FirmwareStatusNotificationRequest = OCPP16FirmwareStatusNotificationRequest;
+
 export type IncomingRequestHandler = (
   chargingStation: ChargingStation,
   commandPayload: JsonType
index 35424a78f31945f9d198bf2f1be101d2a41738ac..c2b1f53a55a71cf39029238a417d691fb1612070 100644 (file)
@@ -9,6 +9,8 @@ import {
   OCPP16ConfigurationStatus,
   type OCPP16DataTransferResponse,
   OCPP16DataTransferStatus,
+  type OCPP16DiagnosticsStatusNotificationResponse,
+  type OCPP16FirmwareStatusNotificationResponse,
   type OCPP16HeartbeatResponse,
   type OCPP16StatusNotificationResponse,
   OCPP16TriggerMessageStatus,
@@ -40,6 +42,10 @@ export type MeterValuesResponse = OCPP16MeterValuesResponse;
 
 export type DataTransferResponse = OCPP16DataTransferResponse;
 
+export type DiagnosticsStatusNotificationResponse = OCPP16DiagnosticsStatusNotificationResponse;
+
+export type FirmwareStatusNotificationResponse = OCPP16FirmwareStatusNotificationResponse;
+
 export enum DefaultStatus {
   ACCEPTED = 'Accepted',
   REJECTED = 'Rejected',
index 47d15bb36b3446afde85b6359216426c917219cd..88e1218226293856ecb5a82d50a4be62dfbdf7fa 100644 (file)
@@ -3,3 +3,5 @@ GetDiagnostics:
 TriggerMessage:
   curl -d '[2,"123456789","TriggerMessage",{"requestedMessage":"BootNotification"}]' -H "Content-Type: application/json" -X POST http://localhost:3000/message
   curl -d '[2,"123456789","TriggerMessage",{"requestedMessage":"HeartBeat"}]' -H "Content-Type: application/json" -X POST http://localhost:3000/message
+UpdateFirmware:
+  curl -d '[2,"123456789","UpdateFirmware",{"location":"ftp://localhost","retrieveDate":"2019-01-01T00:00:00.000Z"}]' -H "Content-Type: application/json" -X POST http://localhost:3000/message