Add support for OCPP 1.6 TriggerMessage command
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 5 Sep 2021 17:47:12 +0000 (19:47 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 5 Sep 2021 17:47:12 +0000 (19:47 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
README.md
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/1.6/Responses.ts
src/types/ocpp/Responses.ts
src/utils/Constants.ts

index 1bbe4dd9c7f61340ed4bc5dfae04bfc7b1b14ada..95c44eb900e7c083796f4e8e581819e3b9e79208 100644 (file)
--- a/README.md
+++ b/README.md
@@ -231,7 +231,7 @@ make SUBMODULES_INIT=false
 
 #### Remote Trigger Profile
 
-- :x: TriggerMessage
+- :white_check_mark: TriggerMessage
 
 ## OCPP-J standard parameters supported
 
index fb146eafa1c1cc5bda3cb4fcef92af818cd0572c..e3dd077d6eeac26a03b3eaf75df7d1a84f193d3f 100644 (file)
@@ -78,6 +78,10 @@ export default class ChargingStation {
     return Utils.logPrefix(` ${this.stationInfo.chargingStationId} |`);
   }
 
+  public getBootNotificationRequest(): BootNotificationRequest {
+    return this.bootNotificationRequest;
+  }
+
   public getRandomTagId(): string {
     const index = Math.floor(Math.random() * this.authorizedTags.length);
     return this.authorizedTags[index];
index 1d93726da99d7e3ea92947d32e28219d23cbf9fd..541a27fb631584efdc6a78aa7142b408e70ec672 100644 (file)
@@ -2,8 +2,8 @@
 
 import * as url from 'url';
 
-import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests';
-import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, GetDiagnosticsResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses';
+import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, MessageTrigger, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, OCPP16TriggerMessageRequest, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests';
+import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, GetDiagnosticsResponse, OCPP16TriggerMessageResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses';
 import { ChargingProfilePurposeType, OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile';
 import { Client, FTPResponse } from 'basic-ftp';
 import { IncomingRequestCommand, RequestCommand } from '../../../types/ocpp/Requests';
@@ -399,4 +399,27 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       return Constants.OCPP_RESPONSE_EMPTY;
     }
   }
+
+  private handleRequestTriggerMessage(commandPayload: OCPP16TriggerMessageRequest): OCPP16TriggerMessageResponse {
+    try {
+      switch (commandPayload.requestedMessage) {
+        case MessageTrigger.BootNotification:
+          setTimeout(() => {
+            this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel,
+              this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
+              this.chargingStation.getBootNotificationRequest().firmwareVersion).catch(() => {});
+          }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
+          return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
+        case MessageTrigger.Heartbeat:
+          setTimeout(() => {
+            this.chargingStation.ocppRequestService.sendHeartbeat().catch(() => {});
+          }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
+          return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
+        default:
+          return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
+      }
+    } catch (error) {
+      return this.handleIncomingRequestError(IncomingRequestCommand.TRIGGER_MESSAGE, error, Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED) as OCPP16TriggerMessageResponse;
+    }
+  }
 }
index 873d41a044df6c0484116cba82612010b1934690..860f4b06e14aedf41a8c11f8dea7c63c4f004587 100644 (file)
@@ -14,7 +14,7 @@ export enum OCPP16RequestCommand {
   START_TRANSACTION = 'StartTransaction',
   STOP_TRANSACTION = 'StopTransaction',
   METER_VALUES = 'MeterValues',
-  DIAGNOSTICS_STATUS_NOTIFICATION= 'DiagnosticsStatusNotification'
+  DIAGNOSTICS_STATUS_NOTIFICATION = 'DiagnosticsStatusNotification'
 }
 
 export enum OCPP16IncomingRequestCommand {
@@ -28,7 +28,8 @@ export enum OCPP16IncomingRequestCommand {
   CLEAR_CHARGING_PROFILE = 'ClearChargingProfile',
   REMOTE_START_TRANSACTION = 'RemoteStartTransaction',
   REMOTE_STOP_TRANSACTION = 'RemoteStopTransaction',
-  GET_DIAGNOSTICS = 'GetDiagnostics'
+  GET_DIAGNOSTICS = 'GetDiagnostics',
+  TRIGGER_MESSAGE = 'TriggerMessage'
 }
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
@@ -121,3 +122,17 @@ export interface GetDiagnosticsRequest {
 export interface DiagnosticsStatusNotificationRequest {
   status: OCPP16DiagnosticsStatus
 }
+
+export enum MessageTrigger {
+  BootNotification = 'BootNotification',
+  DiagnosticsStatusNotification = 'DiagnosticsStatusNotification',
+  FirmwareStatusNotification = 'FirmwareStatusNotification',
+  Heartbeat = 'Heartbeat',
+  MeterValues = 'MeterValues',
+  StatusNotification = 'StatusNotification'
+}
+
+export interface OCPP16TriggerMessageRequest {
+  requestedMessage: MessageTrigger;
+  connectorId?: number
+}
index 68df3e91090ac8c6e2e380962c1d49e98e7596c9..cf0a84ef750d08cd71e3d75f58ae298805e5066a 100644 (file)
@@ -80,3 +80,13 @@ export interface GetDiagnosticsResponse {
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
 export interface DiagnosticsStatusNotificationResponse {}
+
+export enum OCPP16TriggerMessageStatus {
+  ACCEPTED = 'Accepted',
+  REJECTED = 'Rejected',
+  NOT_IMPLEMENTED = 'NotImplemented'
+}
+
+export interface OCPP16TriggerMessageResponse {
+  status: OCPP16TriggerMessageStatus
+}
index a09da33b0fe86af5e6fa9cdcdff120c8b1c71180..77497074221dd2a496e9e2b93ad26bc7f0d5dc5c 100644 (file)
@@ -1,4 +1,4 @@
-import { OCPP16AvailabilityStatus, OCPP16BootNotificationResponse, OCPP16ChargingProfileStatus, OCPP16ClearChargingProfileStatus, OCPP16ConfigurationStatus, OCPP16RegistrationStatus, OCPP16UnlockStatus } from './1.6/Responses';
+import { OCPP16AvailabilityStatus, OCPP16BootNotificationResponse, OCPP16ChargingProfileStatus, OCPP16ClearChargingProfileStatus, OCPP16ConfigurationStatus, OCPP16RegistrationStatus, OCPP16TriggerMessageStatus, OCPP16UnlockStatus } from './1.6/Responses';
 
 export type BootNotificationResponse = OCPP16BootNotificationResponse;
 
@@ -46,3 +46,9 @@ export type UnlockStatus = OCPP16UnlockStatus;
 export const UnlockStatus = {
   ...OCPP16UnlockStatus
 };
+
+export type TriggerMessageStatus = OCPP16TriggerMessageStatus;
+
+export const TriggerMessageStatus = {
+  ...OCPP16TriggerMessageStatus
+};
index c83340e4950d36177eb29c358b4b19130f604688..593aa42a2405341ee4ecdc3d21f4f1ba9e7b8319 100644 (file)
@@ -1,4 +1,4 @@
-import { AvailabilityStatus, ChargingProfileStatus, ClearChargingProfileStatus, ConfigurationStatus, DefaultStatus, UnlockStatus } from '../types/ocpp/Responses';
+import { AvailabilityStatus, ChargingProfileStatus, ClearChargingProfileStatus, ConfigurationStatus, DefaultStatus, TriggerMessageStatus, UnlockStatus } from '../types/ocpp/Responses';
 
 import { MeterValueMeasurand } from '../types/ocpp/MeterValues';
 
@@ -21,9 +21,13 @@ export default class Constants {
   static readonly OCPP_AVAILABILITY_RESPONSE_ACCEPTED = Object.freeze({ status: AvailabilityStatus.ACCEPTED });
   static readonly OCPP_AVAILABILITY_RESPONSE_REJECTED = Object.freeze({ status: AvailabilityStatus.REJECTED });
   static readonly OCPP_AVAILABILITY_RESPONSE_SCHEDULED = Object.freeze({ status: AvailabilityStatus.SCHEDULED });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED = Object.freeze({ status: TriggerMessageStatus.ACCEPTED });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED = Object.freeze({ status: TriggerMessageStatus.REJECTED });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED = Object.freeze({ status: TriggerMessageStatus.NOT_IMPLEMENTED });
 
   static readonly OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL = 60000; // Ms
   static readonly OCPP_ERROR_TIMEOUT = 60000; // Ms
+  static readonly OCPP_TRIGGER_MESSAGE_DELAY = 2000; // Ms
 
   static readonly CHARGING_STATION_DEFAULT_RESET_TIME = 60000; // Ms
   static readonly CHARGING_STATION_ATG_WAIT_TIME = 2000; // Ms