fix: send preparing connector status before `StartTransaction`
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 2.0 / OCPP20RequestService.ts
1 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
2
3 import type { ValidateFunction } from 'ajv'
4
5 import type { ChargingStation } from '../../../charging-station/index.js'
6 import { OCPPError } from '../../../exception/index.js'
7 import {
8 ErrorType,
9 type JsonObject,
10 type JsonType,
11 type OCPP20BootNotificationRequest,
12 type OCPP20HeartbeatRequest,
13 OCPP20RequestCommand,
14 type OCPP20StatusNotificationRequest,
15 OCPPVersion,
16 type RequestParams
17 } from '../../../types/index.js'
18 import { generateUUID } from '../../../utils/index.js'
19 import { OCPPRequestService } from '../OCPPRequestService.js'
20 import type { OCPPResponseService } from '../OCPPResponseService.js'
21 import { OCPP20Constants } from './OCPP20Constants.js'
22 import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
23
24 const moduleName = 'OCPP20RequestService'
25
26 export class OCPP20RequestService extends OCPPRequestService {
27 protected payloadValidateFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
28
29 public constructor (ocppResponseService: OCPPResponseService) {
30 // if (new.target.name === moduleName) {
31 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
32 // }
33 super(OCPPVersion.VERSION_201, ocppResponseService)
34 this.payloadValidateFunctions = new Map<OCPP20RequestCommand, ValidateFunction<JsonType>>([
35 [
36 OCPP20RequestCommand.BOOT_NOTIFICATION,
37 this.ajv
38 .compile(
39 OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationRequest>(
40 'assets/json-schemas/ocpp/2.0/BootNotificationRequest.json',
41 moduleName,
42 'constructor'
43 )
44 )
45 .bind(this)
46 ],
47 [
48 OCPP20RequestCommand.HEARTBEAT,
49 this.ajv
50 .compile(
51 OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatRequest>(
52 'assets/json-schemas/ocpp/2.0/HeartbeatRequest.json',
53 moduleName,
54 'constructor'
55 )
56 )
57 .bind(this)
58 ],
59 [
60 OCPP20RequestCommand.STATUS_NOTIFICATION,
61 this.ajv
62 .compile(
63 OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationRequest>(
64 'assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json',
65 moduleName,
66 'constructor'
67 )
68 )
69 .bind(this)
70 ]
71 ])
72 this.buildRequestPayload = this.buildRequestPayload.bind(this)
73 }
74
75 public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
76 chargingStation: ChargingStation,
77 commandName: OCPP20RequestCommand,
78 commandParams?: RequestType,
79 params?: RequestParams
80 ): Promise<ResponseType> {
81 // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
82 if (OCPP20ServiceUtils.isRequestCommandSupported(chargingStation, commandName)) {
83 // TODO: post request actions hook
84 return (await this.sendMessage(
85 chargingStation,
86 generateUUID(),
87 this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams),
88 commandName,
89 params
90 )) as ResponseType
91 }
92 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
93 throw new OCPPError(
94 ErrorType.NOT_SUPPORTED,
95 `Unsupported OCPP command '${commandName}'`,
96 commandName,
97 commandParams
98 )
99 }
100
101 private buildRequestPayload<Request extends JsonType>(
102 chargingStation: ChargingStation,
103 commandName: OCPP20RequestCommand,
104 commandParams?: JsonType
105 ): Request {
106 commandParams = commandParams as JsonObject
107 switch (commandName) {
108 case OCPP20RequestCommand.BOOT_NOTIFICATION:
109 return commandParams as unknown as Request
110 case OCPP20RequestCommand.HEARTBEAT:
111 return OCPP20Constants.OCPP_RESPONSE_EMPTY as unknown as Request
112 case OCPP20RequestCommand.STATUS_NOTIFICATION:
113 return {
114 timestamp: new Date(),
115 ...commandParams
116 } as unknown as Request
117 default:
118 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
119 throw new OCPPError(
120 ErrorType.NOT_SUPPORTED,
121 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
122 `Unsupported OCPP command '${commandName}'`,
123 commandName,
124 commandParams
125 )
126 }
127 }
128 }