Ensure MeterValues command payload is properly formed
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16RequestService.ts
1 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
3 import OCPPError from '../../../exception/OCPPError';
4 import { JsonObject, JsonType } from '../../../types/JsonType';
5 import { OCPP16RequestCommand } from '../../../types/ocpp/1.6/Requests';
6 import { ErrorType } from '../../../types/ocpp/ErrorType';
7 import { RequestParams } from '../../../types/ocpp/Requests';
8 import Constants from '../../../utils/Constants';
9 import Utils from '../../../utils/Utils';
10 import type ChargingStation from '../../ChargingStation';
11 import OCPPRequestService from '../OCPPRequestService';
12 import type OCPPResponseService from '../OCPPResponseService';
13 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
14
15 const moduleName = 'OCPP16RequestService';
16
17 export default class OCPP16RequestService extends OCPPRequestService {
18 public constructor(ocppResponseService: OCPPResponseService) {
19 if (new.target?.name === moduleName) {
20 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
21 }
22 super(ocppResponseService);
23 }
24
25 public async requestHandler<Request extends JsonType, Response extends JsonType>(
26 chargingStation: ChargingStation,
27 commandName: OCPP16RequestCommand,
28 commandParams?: JsonType,
29 params?: RequestParams
30 ): Promise<Response> {
31 if (Object.values(OCPP16RequestCommand).includes(commandName)) {
32 return (await this.sendMessage(
33 chargingStation,
34 Utils.generateUUID(),
35 this.buildRequestPayload<Request>(chargingStation, commandName, commandParams),
36 commandName,
37 params
38 )) as unknown as Response;
39 }
40 throw new OCPPError(
41 ErrorType.NOT_SUPPORTED,
42 `${moduleName}.requestHandler: Unsupported OCPP command ${commandName}`,
43 commandName,
44 commandParams
45 );
46 }
47
48 private buildRequestPayload<Request extends JsonType>(
49 chargingStation: ChargingStation,
50 commandName: OCPP16RequestCommand,
51 commandParams?: JsonType
52 ): Request {
53 let connectorId: number;
54 commandParams = commandParams as JsonObject;
55 switch (commandName) {
56 case OCPP16RequestCommand.AUTHORIZE:
57 return {
58 ...(!Utils.isUndefined(commandParams?.idTag)
59 ? { idTag: commandParams.idTag }
60 : { idTag: Constants.DEFAULT_IDTAG }),
61 } as unknown as Request;
62 case OCPP16RequestCommand.BOOT_NOTIFICATION:
63 return {
64 chargePointModel: commandParams?.chargePointModel,
65 chargePointVendor: commandParams?.chargePointVendor,
66 ...(!Utils.isUndefined(commandParams?.chargeBoxSerialNumber) && {
67 chargeBoxSerialNumber: commandParams.chargeBoxSerialNumber,
68 }),
69 ...(!Utils.isUndefined(commandParams?.chargePointSerialNumber) && {
70 chargePointSerialNumber: commandParams.chargePointSerialNumber,
71 }),
72 ...(!Utils.isUndefined(commandParams?.firmwareVersion) && {
73 firmwareVersion: commandParams.firmwareVersion,
74 }),
75 ...(!Utils.isUndefined(commandParams?.iccid) && { iccid: commandParams.iccid }),
76 ...(!Utils.isUndefined(commandParams?.imsi) && { imsi: commandParams.imsi }),
77 ...(!Utils.isUndefined(commandParams?.meterSerialNumber) && {
78 meterSerialNumber: commandParams.meterSerialNumber,
79 }),
80 ...(!Utils.isUndefined(commandParams?.meterType) && {
81 meterType: commandParams.meterType,
82 }),
83 } as unknown as Request;
84 case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
85 return {
86 status: commandParams?.diagnosticsStatus,
87 } as unknown as Request;
88 case OCPP16RequestCommand.HEARTBEAT:
89 return {} as unknown as Request;
90 case OCPP16RequestCommand.METER_VALUES:
91 // Sanity check
92 if (!Array.isArray(commandParams?.meterValue)) {
93 throw new OCPPError(
94 ErrorType.TYPERAINT_VIOLATION,
95 `${moduleName}.buildRequestPayload ${commandName}: Invalid array type for meterValue payload field`,
96 commandName,
97 commandParams
98 );
99 }
100 return {
101 connectorId: commandParams?.connectorId,
102 transactionId: commandParams?.transactionId,
103 meterValue: commandParams?.meterValue,
104 } as unknown as Request;
105 case OCPP16RequestCommand.STATUS_NOTIFICATION:
106 return {
107 connectorId: commandParams?.connectorId,
108 status: commandParams?.status,
109 errorCode: commandParams?.errorCode,
110 } as unknown as Request;
111 case OCPP16RequestCommand.START_TRANSACTION:
112 return {
113 connectorId: commandParams?.connectorId,
114 ...(!Utils.isUndefined(commandParams?.idTag)
115 ? { idTag: commandParams?.idTag }
116 : { idTag: Constants.DEFAULT_IDTAG }),
117 meterStart: chargingStation.getEnergyActiveImportRegisterByConnectorId(
118 commandParams?.connectorId as number
119 ),
120 timestamp: new Date().toISOString(),
121 } as unknown as Request;
122 case OCPP16RequestCommand.STOP_TRANSACTION:
123 connectorId = chargingStation.getConnectorIdByTransactionId(
124 commandParams?.transactionId as number
125 );
126 return {
127 transactionId: commandParams?.transactionId,
128 ...(!Utils.isUndefined(commandParams?.idTag) && { idTag: commandParams.idTag }),
129 meterStop: commandParams?.meterStop,
130 timestamp: new Date().toISOString(),
131 ...(commandParams?.reason && { reason: commandParams.reason }),
132 ...(chargingStation.getTransactionDataMeterValues() && {
133 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
134 chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue,
135 OCPP16ServiceUtils.buildTransactionEndMeterValue(
136 chargingStation,
137 connectorId,
138 commandParams?.meterStop as number
139 )
140 ),
141 }),
142 } as unknown as Request;
143 default:
144 throw new OCPPError(
145 ErrorType.NOT_SUPPORTED,
146 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
147 `${moduleName}.buildRequestPayload: Unsupported OCPP command: ${commandName}`,
148 commandName,
149 commandParams
150 );
151 }
152 }
153 }