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 OCPP20IncomingRequestCommand
,
15 } from
'../../../types/ocpp/2.0/Requests';
17 OCPP20BootNotificationResponse
,
18 OCPP20ClearCacheResponse
,
19 OCPP20HeartbeatResponse
,
20 OCPP20StatusNotificationResponse
,
21 } from
'../../../types/ocpp/2.0/Responses';
22 import { ErrorType
} from
'../../../types/ocpp/ErrorType';
23 import { OCPPVersion
} from
'../../../types/ocpp/OCPPVersion';
24 import { RegistrationStatusEnumType
, ResponseHandler
} from
'../../../types/ocpp/Responses';
25 import logger from
'../../../utils/Logger';
26 import type ChargingStation from
'../../ChargingStation';
27 import OCPPResponseService from
'../OCPPResponseService';
29 const moduleName
= 'OCPP20ResponseService';
31 export default class OCPP20ResponseService
extends OCPPResponseService
{
32 public jsonIncomingRequestResponseSchemas
: Map
<
33 OCPP20IncomingRequestCommand
,
34 JSONSchemaType
<JsonObject
>
37 private responseHandlers
: Map
<OCPP20RequestCommand
, ResponseHandler
>;
38 private jsonSchemas
: Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>;
40 public constructor() {
41 if (new.target
?.name
=== moduleName
) {
42 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
44 super(OCPPVersion
.VERSION_20
);
45 this.responseHandlers
= new Map
<OCPP20RequestCommand
, ResponseHandler
>([
46 [OCPP20RequestCommand
.BOOT_NOTIFICATION
, this.handleResponseBootNotification
.bind(this)],
47 [OCPP20RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
.bind(this)],
48 [OCPP20RequestCommand
.STATUS_NOTIFICATION
, this.emptyResponseHandler
.bind(this)],
50 this.jsonSchemas
= new Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>([
52 OCPP20RequestCommand
.BOOT_NOTIFICATION
,
53 this.parseJsonSchemaFile
<OCPP20BootNotificationResponse
>(
54 '../../../assets/json-schemas/ocpp/2.0/BootNotificationResponse.json'
58 OCPP20RequestCommand
.HEARTBEAT
,
59 this.parseJsonSchemaFile
<OCPP20HeartbeatResponse
>(
60 '../../../assets/json-schemas/ocpp/2.0/HeartbeatResponse.json'
64 OCPP20RequestCommand
.STATUS_NOTIFICATION
,
65 this.parseJsonSchemaFile
<OCPP20StatusNotificationResponse
>(
66 '../../../assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json'
70 this.jsonIncomingRequestResponseSchemas
= new Map([
72 OCPP20IncomingRequestCommand
.CLEAR_CACHE
,
73 this.parseJsonSchemaFile
<OCPP20ClearCacheResponse
>(
74 '../../../assets/json-schemas/ocpp/2.0/ClearCacheResponse.json'
78 this.validatePayload
.bind(this);
81 public async responseHandler(
82 chargingStation
: ChargingStation
,
83 commandName
: OCPP20RequestCommand
,
85 requestPayload
: JsonType
88 chargingStation
.isRegistered() === true ||
89 commandName
=== OCPP20RequestCommand
.BOOT_NOTIFICATION
92 this.responseHandlers
.has(commandName
) === true &&
93 OCPP20ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true
96 this.validatePayload(chargingStation
, commandName
, payload
);
97 await this.responseHandlers
.get(commandName
)(chargingStation
, payload
, requestPayload
);
100 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
108 ErrorType
.NOT_IMPLEMENTED
,
109 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
120 ErrorType
.SECURITY_ERROR
,
121 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
125 )} while the charging station is not registered on the central server.`,
132 private validatePayload(
133 chargingStation
: ChargingStation
,
134 commandName
: OCPP20RequestCommand
,
137 if (this.jsonSchemas
.has(commandName
) === true) {
138 return this.validateResponsePayload(
141 this.jsonSchemas
.get(commandName
),
146 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
151 private handleResponseBootNotification(
152 chargingStation
: ChargingStation
,
153 payload
: OCPP20BootNotificationResponse
155 if (payload
.status === RegistrationStatusEnumType
.ACCEPTED
) {
156 // ChargingStationConfigurationUtils.addConfigurationKey(
158 // OCPP16StandardParametersKey.HeartbeatInterval,
159 // payload.interval.toString(),
161 // { overwrite: true, save: true }
163 // ChargingStationConfigurationUtils.addConfigurationKey(
165 // OCPP16StandardParametersKey.HeartBeatInterval,
166 // payload.interval.toString(),
167 // { visible: false },
168 // { overwrite: true, save: true }
170 chargingStation
.heartbeatSetInterval
171 ? chargingStation
.restartHeartbeat()
172 : chargingStation
.startHeartbeat();
174 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
175 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
177 }' state on the central server`;
178 payload
.status === RegistrationStatusEnumType
.REJECTED
179 ? logger
.warn(logMsg
)
180 : logger
.info(logMsg
);
183 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
189 private parseJsonSchemaFile
<T
extends JsonType
>(relativePath
: string): JSONSchemaType
<T
> {
192 path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), relativePath
),
195 ) as JSONSchemaType
<T
>;