1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import type { JSONSchemaType
} from
'ajv';
5 import { OCPP20ServiceUtils
} from
'./OCPP20ServiceUtils';
6 import OCPPError from
'../../../exception/OCPPError';
7 import type { JsonObject
, JsonType
} from
'../../../types/JsonType';
9 OCPP20IncomingRequestCommand
,
11 } from
'../../../types/ocpp/2.0/Requests';
13 OCPP20BootNotificationResponse
,
14 OCPP20ClearCacheResponse
,
15 OCPP20HeartbeatResponse
,
16 OCPP20StatusNotificationResponse
,
17 } from
'../../../types/ocpp/2.0/Responses';
18 import { ErrorType
} from
'../../../types/ocpp/ErrorType';
19 import { OCPPVersion
} from
'../../../types/ocpp/OCPPVersion';
20 import { RegistrationStatusEnumType
, ResponseHandler
} from
'../../../types/ocpp/Responses';
21 import logger from
'../../../utils/Logger';
22 import type ChargingStation from
'../../ChargingStation';
23 import OCPPResponseService from
'../OCPPResponseService';
25 const moduleName
= 'OCPP20ResponseService';
27 export default class OCPP20ResponseService
extends OCPPResponseService
{
28 public jsonIncomingRequestResponseSchemas
: Map
<
29 OCPP20IncomingRequestCommand
,
30 JSONSchemaType
<JsonObject
>
33 private responseHandlers
: Map
<OCPP20RequestCommand
, ResponseHandler
>;
34 private jsonSchemas
: Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>;
36 public constructor() {
37 if (new.target
?.name
=== moduleName
) {
38 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
40 super(OCPPVersion
.VERSION_20
);
41 this.responseHandlers
= new Map
<OCPP20RequestCommand
, ResponseHandler
>([
42 [OCPP20RequestCommand
.BOOT_NOTIFICATION
, this.handleResponseBootNotification
.bind(this)],
43 [OCPP20RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
.bind(this)],
44 [OCPP20RequestCommand
.STATUS_NOTIFICATION
, this.emptyResponseHandler
.bind(this)],
46 this.jsonSchemas
= new Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>([
48 OCPP20RequestCommand
.BOOT_NOTIFICATION
,
49 OCPP20ServiceUtils
.parseJsonSchemaFile
<OCPP20BootNotificationResponse
>(
50 '../../../assets/json-schemas/ocpp/2.0/BootNotificationResponse.json'
54 OCPP20RequestCommand
.HEARTBEAT
,
55 OCPP20ServiceUtils
.parseJsonSchemaFile
<OCPP20HeartbeatResponse
>(
56 '../../../assets/json-schemas/ocpp/2.0/HeartbeatResponse.json'
60 OCPP20RequestCommand
.STATUS_NOTIFICATION
,
61 OCPP20ServiceUtils
.parseJsonSchemaFile
<OCPP20StatusNotificationResponse
>(
62 '../../../assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json'
66 this.jsonIncomingRequestResponseSchemas
= new Map([
68 OCPP20IncomingRequestCommand
.CLEAR_CACHE
,
69 OCPP20ServiceUtils
.parseJsonSchemaFile
<OCPP20ClearCacheResponse
>(
70 '../../../assets/json-schemas/ocpp/2.0/ClearCacheResponse.json'
74 this.validatePayload
.bind(this);
77 public async responseHandler(
78 chargingStation
: ChargingStation
,
79 commandName
: OCPP20RequestCommand
,
81 requestPayload
: JsonType
84 chargingStation
.isRegistered() === true ||
85 commandName
=== OCPP20RequestCommand
.BOOT_NOTIFICATION
88 this.responseHandlers
.has(commandName
) === true &&
89 OCPP20ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true
92 this.validatePayload(chargingStation
, commandName
, payload
);
93 await this.responseHandlers
.get(commandName
)(chargingStation
, payload
, requestPayload
);
96 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
104 ErrorType
.NOT_IMPLEMENTED
,
105 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
116 ErrorType
.SECURITY_ERROR
,
117 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
121 )} while the charging station is not registered on the central server.`,
128 private validatePayload(
129 chargingStation
: ChargingStation
,
130 commandName
: OCPP20RequestCommand
,
133 if (this.jsonSchemas
.has(commandName
) === true) {
134 return this.validateResponsePayload(
137 this.jsonSchemas
.get(commandName
),
142 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
147 private handleResponseBootNotification(
148 chargingStation
: ChargingStation
,
149 payload
: OCPP20BootNotificationResponse
151 if (payload
.status === RegistrationStatusEnumType
.ACCEPTED
) {
152 // ChargingStationConfigurationUtils.addConfigurationKey(
154 // OCPP16StandardParametersKey.HeartbeatInterval,
155 // payload.interval.toString(),
157 // { overwrite: true, save: true }
159 // ChargingStationConfigurationUtils.addConfigurationKey(
161 // OCPP16StandardParametersKey.HeartBeatInterval,
162 // payload.interval.toString(),
163 // { visible: false },
164 // { overwrite: true, save: true }
166 chargingStation
.heartbeatSetInterval
167 ? chargingStation
.restartHeartbeat()
168 : chargingStation
.startHeartbeat();
170 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
171 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
173 }' state on the central server`;
174 payload
.status === RegistrationStatusEnumType
.REJECTED
175 ? logger
.warn(logMsg
)
176 : logger
.info(logMsg
);
179 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,