Commit | Line | Data |
---|---|---|
6c1761d4 | 1 | import type { DefinedError, ErrorObject } from 'ajv'; |
06ad945f | 2 | |
884a6fdf JB |
3 | import BaseError from '../../exception/BaseError'; |
4 | import type { SampledValueTemplate } from '../../types/MeasurandPerPhaseSampledValueTemplates'; | |
5 | import { StandardParametersKey } from '../../types/ocpp/Configuration'; | |
06ad945f | 6 | import { ErrorType } from '../../types/ocpp/ErrorType'; |
884a6fdf | 7 | import { MeterValueMeasurand, type MeterValuePhase } from '../../types/ocpp/MeterValues'; |
ed3d2808 | 8 | import { IncomingRequestCommand, RequestCommand } from '../../types/ocpp/Requests'; |
884a6fdf | 9 | import Constants from '../../utils/Constants'; |
ed3d2808 | 10 | import logger from '../../utils/Logger'; |
884a6fdf | 11 | import Utils from '../../utils/Utils'; |
ed3d2808 | 12 | import type ChargingStation from '../ChargingStation'; |
884a6fdf | 13 | import { ChargingStationConfigurationUtils } from '../ChargingStationConfigurationUtils'; |
06ad945f | 14 | |
90befdb8 | 15 | export class OCPPServiceUtils { |
d5bd1c00 JB |
16 | protected constructor() { |
17 | // This is intentional | |
18 | } | |
19 | ||
01a4dcbb | 20 | public static ajvErrorsToErrorType(errors: ErrorObject[]): ErrorType { |
06ad945f JB |
21 | for (const error of errors as DefinedError[]) { |
22 | switch (error.keyword) { | |
23 | case 'type': | |
24 | return ErrorType.TYPE_CONSTRAINT_VIOLATION; | |
25 | case 'dependencies': | |
26 | case 'required': | |
27 | return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION; | |
28 | case 'pattern': | |
29 | case 'format': | |
30 | return ErrorType.PROPERTY_CONSTRAINT_VIOLATION; | |
31 | } | |
32 | } | |
33 | return ErrorType.FORMAT_VIOLATION; | |
34 | } | |
35 | ||
ed3d2808 | 36 | public static isRequestCommandSupported( |
fd3c56d1 JB |
37 | chargingStation: ChargingStation, |
38 | command: RequestCommand | |
ed3d2808 JB |
39 | ): boolean { |
40 | const isRequestCommand = Object.values(RequestCommand).includes(command); | |
41 | if ( | |
42 | isRequestCommand === true && | |
43 | !chargingStation.stationInfo?.commandsSupport?.outgoingCommands | |
44 | ) { | |
45 | return true; | |
46 | } else if ( | |
47 | isRequestCommand === true && | |
48 | chargingStation.stationInfo?.commandsSupport?.outgoingCommands | |
49 | ) { | |
50 | return chargingStation.stationInfo?.commandsSupport?.outgoingCommands[command] ?? false; | |
51 | } | |
52 | logger.error(`${chargingStation.logPrefix()} Unknown outgoing OCPP command '${command}'`); | |
53 | return false; | |
54 | } | |
55 | ||
56 | public static isIncomingRequestCommandSupported( | |
fd3c56d1 JB |
57 | chargingStation: ChargingStation, |
58 | command: IncomingRequestCommand | |
ed3d2808 JB |
59 | ): boolean { |
60 | const isIncomingRequestCommand = Object.values(IncomingRequestCommand).includes(command); | |
61 | if ( | |
62 | isIncomingRequestCommand === true && | |
63 | !chargingStation.stationInfo?.commandsSupport?.incomingCommands | |
64 | ) { | |
65 | return true; | |
66 | } else if ( | |
67 | isIncomingRequestCommand === true && | |
68 | chargingStation.stationInfo?.commandsSupport?.incomingCommands | |
69 | ) { | |
70 | return chargingStation.stationInfo?.commandsSupport?.incomingCommands[command] ?? false; | |
71 | } | |
72 | logger.error(`${chargingStation.logPrefix()} Unknown incoming OCPP command '${command}'`); | |
73 | return false; | |
74 | } | |
75 | ||
884a6fdf JB |
76 | protected static getSampledValueTemplate( |
77 | chargingStation: ChargingStation, | |
78 | connectorId: number, | |
79 | measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER, | |
80 | phase?: MeterValuePhase | |
81 | ): SampledValueTemplate | undefined { | |
82 | const onPhaseStr = phase ? `on phase ${phase} ` : ''; | |
83 | if (Constants.SUPPORTED_MEASURANDS.includes(measurand) === false) { | |
84 | logger.warn( | |
85 | `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` | |
86 | ); | |
87 | return; | |
88 | } | |
89 | if ( | |
90 | measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && | |
23290150 | 91 | ChargingStationConfigurationUtils.getConfigurationKey( |
884a6fdf JB |
92 | chargingStation, |
93 | StandardParametersKey.MeterValuesSampledData | |
23290150 | 94 | )?.value.includes(measurand) === false |
884a6fdf JB |
95 | ) { |
96 | logger.debug( | |
97 | `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId} not found in '${ | |
98 | StandardParametersKey.MeterValuesSampledData | |
99 | }' OCPP parameter` | |
100 | ); | |
101 | return; | |
102 | } | |
103 | const sampledValueTemplates: SampledValueTemplate[] = | |
104 | chargingStation.getConnectorStatus(connectorId).MeterValues; | |
105 | for ( | |
106 | let index = 0; | |
23290150 | 107 | Utils.isEmptyArray(sampledValueTemplates) === false && index < sampledValueTemplates.length; |
884a6fdf JB |
108 | index++ |
109 | ) { | |
110 | if ( | |
111 | Constants.SUPPORTED_MEASURANDS.includes( | |
112 | sampledValueTemplates[index]?.measurand ?? | |
113 | MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER | |
114 | ) === false | |
115 | ) { | |
116 | logger.warn( | |
117 | `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` | |
118 | ); | |
119 | } else if ( | |
120 | phase && | |
121 | sampledValueTemplates[index]?.phase === phase && | |
122 | sampledValueTemplates[index]?.measurand === measurand && | |
123 | ChargingStationConfigurationUtils.getConfigurationKey( | |
124 | chargingStation, | |
125 | StandardParametersKey.MeterValuesSampledData | |
126 | )?.value.includes(measurand) === true | |
127 | ) { | |
128 | return sampledValueTemplates[index]; | |
129 | } else if ( | |
130 | !phase && | |
131 | !sampledValueTemplates[index].phase && | |
132 | sampledValueTemplates[index]?.measurand === measurand && | |
133 | ChargingStationConfigurationUtils.getConfigurationKey( | |
134 | chargingStation, | |
135 | StandardParametersKey.MeterValuesSampledData | |
136 | )?.value.includes(measurand) === true | |
137 | ) { | |
138 | return sampledValueTemplates[index]; | |
139 | } else if ( | |
140 | measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && | |
141 | (!sampledValueTemplates[index].measurand || | |
142 | sampledValueTemplates[index].measurand === measurand) | |
143 | ) { | |
144 | return sampledValueTemplates[index]; | |
145 | } | |
146 | } | |
147 | if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) { | |
148 | const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connectorId ${connectorId}`; | |
149 | logger.error(`${chargingStation.logPrefix()} ${errorMsg}`); | |
150 | throw new BaseError(errorMsg); | |
151 | } | |
152 | logger.debug( | |
153 | `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}` | |
154 | ); | |
155 | } | |
156 | ||
90befdb8 JB |
157 | protected static getLimitFromSampledValueTemplateCustomValue( |
158 | value: string, | |
159 | limit: number, | |
160 | options: { limitationEnabled?: boolean; unitMultiplier?: number } = { | |
161 | limitationEnabled: true, | |
162 | unitMultiplier: 1, | |
163 | } | |
164 | ): number { | |
165 | options.limitationEnabled = options?.limitationEnabled ?? true; | |
166 | options.unitMultiplier = options?.unitMultiplier ?? 1; | |
f126aa15 | 167 | const numberValue = isNaN(parseInt(value)) ? Infinity : parseInt(value); |
90befdb8 | 168 | return options?.limitationEnabled |
f126aa15 JB |
169 | ? Math.min(numberValue * options.unitMultiplier, limit) |
170 | : numberValue * options.unitMultiplier; | |
90befdb8 JB |
171 | } |
172 | } |