1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
4 import path from
'path';
5 import { fileURLToPath
} from
'url';
7 import type { JSONSchemaType
} from
'ajv';
9 import { OCPP20ServiceUtils
} from
'./OCPP20ServiceUtils';
10 import OCPPError from
'../../../exception/OCPPError';
11 import type { JsonObject
, JsonType
} from
'../../../types/JsonType';
13 type OCPP20BootNotificationRequest
,
14 type OCPP20HeartbeatRequest
,
16 type OCPP20StatusNotificationRequest
,
17 } from
'../../../types/ocpp/2.0/Requests';
18 import { ErrorType
} from
'../../../types/ocpp/ErrorType';
19 import { OCPPVersion
} from
'../../../types/ocpp/OCPPVersion';
20 import type { RequestParams
} from
'../../../types/ocpp/Requests';
21 import Utils from
'../../../utils/Utils';
22 import type ChargingStation from
'../../ChargingStation';
23 import OCPPConstants from
'../OCPPConstants';
24 import OCPPRequestService from
'../OCPPRequestService';
25 import type OCPPResponseService from
'../OCPPResponseService';
27 const moduleName
= 'OCPP20RequestService';
29 export default class OCPP20RequestService
extends OCPPRequestService
{
30 protected jsonSchemas
: Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>;
32 public constructor(ocppResponseService
: OCPPResponseService
) {
33 if (new.target
?.name
=== moduleName
) {
34 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
36 super(OCPPVersion
.VERSION_20
, ocppResponseService
);
37 this.jsonSchemas
= new Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>([
39 OCPP20RequestCommand
.BOOT_NOTIFICATION
,
40 this.parseJsonSchemaFile
<OCPP20BootNotificationRequest
>(
41 '../../../assets/json-schemas/ocpp/2.0/BootNotificationRequest.json'
45 OCPP20RequestCommand
.HEARTBEAT
,
46 this.parseJsonSchemaFile
<OCPP20HeartbeatRequest
>(
47 '../../../assets/json-schemas/ocpp/2.0/HeartbeatRequest.json'
51 OCPP20RequestCommand
.STATUS_NOTIFICATION
,
52 this.parseJsonSchemaFile
<OCPP20StatusNotificationRequest
>(
53 '../../../assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json'
57 this.buildRequestPayload
.bind(this);
60 public async requestHandler
<RequestType
extends JsonType
, ResponseType
extends JsonType
>(
61 chargingStation
: ChargingStation
,
62 commandName
: OCPP20RequestCommand
,
63 commandParams
?: JsonType
,
64 params
?: RequestParams
65 ): Promise
<ResponseType
> {
66 if (OCPP20ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true) {
67 const requestPayload
= this.buildRequestPayload
<RequestType
>(
72 return (await this.sendMessage(
78 )) as unknown
as ResponseType
;
80 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
82 ErrorType
.NOT_SUPPORTED
,
83 `Unsupported OCPP command '${commandName}'`,
89 private buildRequestPayload
<Request
extends JsonType
>(
90 chargingStation
: ChargingStation
,
91 commandName
: OCPP20RequestCommand
,
92 commandParams
?: JsonType
94 commandParams
= commandParams
as JsonObject
;
95 switch (commandName
) {
96 case OCPP20RequestCommand
.BOOT_NOTIFICATION
:
97 commandParams
.chargingStation
= commandParams
.chargingStation
as JsonObject
;
98 commandParams
.chargingStation
.modem
= commandParams
.chargingStation
.modem
as JsonObject
;
100 reason
: commandParams
?.reason
,
102 model
: commandParams
?.chargingStation
?.model
,
103 vendorName
: commandParams
?.chargingStation
?.vendorName
,
104 ...(!Utils
.isUndefined(commandParams
?.chargingStation
?.firmwareVersion
) && {
105 firmwareVersion
: commandParams
.chargingStation
?.firmwareVersion
,
107 ...(!Utils
.isUndefined(commandParams
?.chargingStation
?.serialNumber
) && {
108 serialNumber
: commandParams
.chargingStation
?.serialNumber
,
110 ...(!Utils
.isUndefined(commandParams
?.chargingStation
?.modem
) && {
112 ...(!Utils
.isUndefined(commandParams
?.chargingStation
?.modem
?.iccid
) && {
113 iccid
: commandParams
.chargingStation
.modem
.iccid
,
115 ...(!Utils
.isUndefined(commandParams
?.chargingStation
?.modem
?.imsi
) && {
116 imsi
: commandParams
.chargingStation
.modem
.imsi
,
121 } as unknown
as Request
;
122 case OCPP20RequestCommand
.HEARTBEAT
:
123 return OCPPConstants
.OCPP_RESPONSE_EMPTY
as unknown
as Request
;
124 case OCPP20RequestCommand
.STATUS_NOTIFICATION
:
126 timestamp
: commandParams
?.timestamp
?? new Date(),
127 connectorStatus
: commandParams
?.connectorStatus
,
128 evseId
: commandParams
?.evseId
,
129 connectorId
: commandParams
?.connectorId
,
130 } as unknown
as Request
;
132 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
134 ErrorType
.NOT_SUPPORTED
,
135 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
136 `Unsupported OCPP command '${commandName}'`,
143 private parseJsonSchemaFile
<T
extends JsonType
>(relativePath
: string): JSONSchemaType
<T
> {
146 path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), relativePath
),
149 ) as JSONSchemaType
<T
>;