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 OCPPError from
'../../../exception/OCPPError';
10 import type { JsonObject
, JsonType
} from
'../../../types/JsonType';
12 OCPP20IncomingRequestCommand
,
14 } from
'../../../types/ocpp/2.0/Requests';
16 OCPP20BootNotificationResponse
,
17 OCPP20ClearCacheResponse
,
18 OCPP20HeartbeatResponse
,
19 } from
'../../../types/ocpp/2.0/Responses';
20 import { ErrorType
} from
'../../../types/ocpp/ErrorType';
21 import { OCPPVersion
} from
'../../../types/ocpp/OCPPVersion';
22 import { RegistrationStatusEnumType
, ResponseHandler
} from
'../../../types/ocpp/Responses';
23 import logger from
'../../../utils/Logger';
24 import type ChargingStation from
'../../ChargingStation';
25 import OCPPResponseService from
'../OCPPResponseService';
26 import { OCPP20ServiceUtils
} from
'./OCPP20ServiceUtils';
28 const moduleName
= 'OCPP20ResponseService';
30 export default class OCPP20ResponseService
extends OCPPResponseService
{
31 public jsonIncomingRequestResponseSchemas
: Map
<
32 OCPP20IncomingRequestCommand
,
33 JSONSchemaType
<JsonObject
>
36 private responseHandlers
: Map
<OCPP20RequestCommand
, ResponseHandler
>;
37 private jsonSchemas
: Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>;
39 public constructor() {
40 if (new.target
?.name
=== moduleName
) {
41 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
43 super(OCPPVersion
.VERSION_20
);
44 this.responseHandlers
= new Map
<OCPP20RequestCommand
, ResponseHandler
>([
45 [OCPP20RequestCommand
.BOOT_NOTIFICATION
, this.handleResponseBootNotification
.bind(this)],
46 [OCPP20RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
.bind(this)],
48 this.jsonSchemas
= new Map
<OCPP20RequestCommand
, JSONSchemaType
<JsonObject
>>([
50 OCPP20RequestCommand
.BOOT_NOTIFICATION
,
54 path
.dirname(fileURLToPath(import.meta
.url
)),
55 '../../../assets/json-schemas/ocpp/2.0/BootNotificationResponse.json'
59 ) as JSONSchemaType
<OCPP20BootNotificationResponse
>,
62 OCPP20RequestCommand
.HEARTBEAT
,
66 path
.dirname(fileURLToPath(import.meta
.url
)),
67 '../../../assets/json-schemas/ocpp/2.0/HeartbeatResponse.json'
71 ) as JSONSchemaType
<OCPP20HeartbeatResponse
>,
74 this.jsonIncomingRequestResponseSchemas
= new Map([
76 OCPP20IncomingRequestCommand
.CLEAR_CACHE
,
80 path
.dirname(fileURLToPath(import.meta
.url
)),
81 '../../../assets/json-schemas/ocpp/2.0/ClearCacheResponse.json'
85 ) as JSONSchemaType
<OCPP20ClearCacheResponse
>,
88 this.validatePayload
.bind(this);
91 public async responseHandler(
92 chargingStation
: ChargingStation
,
93 commandName
: OCPP20RequestCommand
,
95 requestPayload
: JsonType
98 chargingStation
.isRegistered() === true ||
99 commandName
=== OCPP20RequestCommand
.BOOT_NOTIFICATION
102 this.responseHandlers
.has(commandName
) === true &&
103 OCPP20ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true
106 this.validatePayload(chargingStation
, commandName
, payload
);
107 await this.responseHandlers
.get(commandName
)(chargingStation
, payload
, requestPayload
);
110 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
118 ErrorType
.NOT_IMPLEMENTED
,
119 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
130 ErrorType
.SECURITY_ERROR
,
131 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
135 )} while the charging station is not registered on the central server.`,
142 private validatePayload(
143 chargingStation
: ChargingStation
,
144 commandName
: OCPP20RequestCommand
,
147 if (this.jsonSchemas
.has(commandName
) === true) {
148 return this.validateResponsePayload(
151 this.jsonSchemas
.get(commandName
),
156 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
161 private handleResponseBootNotification(
162 chargingStation
: ChargingStation
,
163 payload
: OCPP20BootNotificationResponse
165 if (payload
.status === RegistrationStatusEnumType
.ACCEPTED
) {
166 // ChargingStationConfigurationUtils.addConfigurationKey(
168 // OCPP16StandardParametersKey.HeartbeatInterval,
169 // payload.interval.toString(),
171 // { overwrite: true, save: true }
173 // ChargingStationConfigurationUtils.addConfigurationKey(
175 // OCPP16StandardParametersKey.HeartBeatInterval,
176 // payload.interval.toString(),
177 // { visible: false },
178 // { overwrite: true, save: true }
180 chargingStation
.heartbeatSetInterval
181 ? chargingStation
.restartHeartbeat()
182 : chargingStation
.startHeartbeat();
184 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
185 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
187 }' state on the central server`;
188 payload
.status === RegistrationStatusEnumType
.REJECTED
189 ? logger
.warn(logMsg
)
190 : logger
.info(logMsg
);
193 chargingStation
.logPrefix() +
194 ' Charging station boot notification response received: %j with undefined registration status',