import BaseError from '../exception/BaseError';
import type OCPPError from '../exception/OCPPError';
+import { StandardParametersKey } from '../types/ocpp/Configuration';
import {
HeartbeatRequest,
+ MeterValuesRequest,
RequestCommand,
type StatusNotificationRequest,
} from '../types/ocpp/Requests';
-import type { HeartbeatResponse, StatusNotificationResponse } from '../types/ocpp/Responses';
+import type {
+ HeartbeatResponse,
+ MeterValuesResponse,
+ StatusNotificationResponse,
+} from '../types/ocpp/Responses';
import {
AuthorizationStatus,
AuthorizeRequest,
MessageEvent,
} from '../types/WorkerBroadcastChannel';
import { ResponseStatus } from '../ui/web/src/types/UIProtocol';
+import Constants from '../utils/Constants';
import logger from '../utils/Logger';
import Utils from '../utils/Utils';
import type ChargingStation from './ChargingStation';
+import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
+import { OCPP16ServiceUtils } from './ocpp/1.6/OCPP16ServiceUtils';
import WorkerBroadcastChannel from './WorkerBroadcastChannel';
const moduleName = 'ChargingStationWorkerBroadcastChannel';
| StopTransactionResponse
| AuthorizeResponse
| StatusNotificationResponse
- | HeartbeatResponse;
+ | HeartbeatResponse
+ | MeterValuesResponse;
type CommandHandler = (
requestPayload?: BroadcastChannelRequestPayload
StartTransactionResponse
>(this.chargingStation, RequestCommand.STOP_TRANSACTION, {
...requestPayload,
- meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
- requestPayload.transactionId,
- true
- ),
+ meterStop:
+ requestPayload.meterStop ??
+ this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
+ requestPayload.transactionId,
+ true
+ ),
}),
],
[
HeartbeatResponse
>(this.chargingStation, RequestCommand.HEARTBEAT, requestPayload),
],
+ [
+ BroadcastChannelProcedureName.METER_VALUES,
+ async (requestPayload?: BroadcastChannelRequestPayload) => {
+ const configuredMeterValueSampleInterval =
+ ChargingStationConfigurationUtils.getConfigurationKey(
+ chargingStation,
+ StandardParametersKey.MeterValueSampleInterval
+ );
+ return this.chargingStation.ocppRequestService.requestHandler<
+ MeterValuesRequest,
+ MeterValuesResponse
+ >(this.chargingStation, RequestCommand.METER_VALUES, {
+ ...requestPayload,
+ meterValue: requestPayload.meterValue ?? [
+ OCPP16ServiceUtils.buildMeterValue(
+ this.chargingStation,
+ requestPayload.connectorId,
+ this.chargingStation.getConnectorStatus(requestPayload.connectorId)?.transactionId,
+ configuredMeterValueSampleInterval
+ ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
+ : Constants.DEFAULT_METER_VALUES_INTERVAL
+ ),
+ ],
+ });
+ },
+ ],
]);
this.chargingStation = chargingStation;
this.onmessage = this.requestHandler.bind(this) as (message: MessageEvent) => void;
status: ResponseStatus.SUCCESS,
};
} else {
- const commandResponseStatus = this.commandResponseToResponseStatus(
+ responsePayload = this.commandResponseToResponsePayload(
command,
+ requestPayload,
commandResponse as CommandResponse
);
- if (commandResponseStatus === ResponseStatus.SUCCESS) {
- responsePayload = {
- hashId: this.chargingStation.stationInfo.hashId,
- status: commandResponseStatus,
- };
- } else {
- responsePayload = {
- hashId: this.chargingStation.stationInfo.hashId,
- status: commandResponseStatus,
- command,
- requestPayload,
- commandResponse: commandResponse as CommandResponse,
- };
- }
}
} catch (error) {
logger.error(
].includes(command) === false && delete requestPayload.connectorIds;
}
- private commandResponseToResponseStatus(
+ private commandResponseToResponsePayload(
+ command: BroadcastChannelProcedureName,
+ requestPayload: BroadcastChannelRequestPayload,
+ commandResponse: CommandResponse
+ ): BroadcastChannelResponsePayload {
+ const commandResponseStatus = this.commandResponseStatusToResponseStatus(
+ command,
+ commandResponse
+ );
+ if (commandResponseStatus === ResponseStatus.SUCCESS) {
+ return {
+ hashId: this.chargingStation.stationInfo.hashId,
+ status: commandResponseStatus,
+ };
+ }
+ return {
+ hashId: this.chargingStation.stationInfo.hashId,
+ status: commandResponseStatus,
+ command,
+ requestPayload,
+ commandResponse,
+ };
+ }
+
+ private commandResponseStatusToResponseStatus(
command: BroadcastChannelProcedureName,
commandResponse: CommandResponse
): ResponseStatus {
}
return ResponseStatus.FAILURE;
case BroadcastChannelProcedureName.STATUS_NOTIFICATION:
+ case BroadcastChannelProcedureName.METER_VALUES:
if (Utils.isEmptyObject(commandResponse) === true) {
return ResponseStatus.SUCCESS;
}
import type { AbstractUIServer } from '../AbstractUIServer';
import AbstractUIService from './AbstractUIService';
-const ProcedureNameToBroadCastChannelProcedureNameMap: Omit<
- Record<ProcedureName, BroadcastChannelProcedureName>,
- 'startSimulator' | 'stopSimulator' | 'listChargingStations'
-> = {
- [ProcedureName.START_CHARGING_STATION]: BroadcastChannelProcedureName.START_CHARGING_STATION,
- [ProcedureName.STOP_CHARGING_STATION]: BroadcastChannelProcedureName.STOP_CHARGING_STATION,
- [ProcedureName.CLOSE_CONNECTION]: BroadcastChannelProcedureName.CLOSE_CONNECTION,
- [ProcedureName.OPEN_CONNECTION]: BroadcastChannelProcedureName.OPEN_CONNECTION,
- [ProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR]:
- BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
- [ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR]:
- BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
- [ProcedureName.START_TRANSACTION]: BroadcastChannelProcedureName.START_TRANSACTION,
- [ProcedureName.STOP_TRANSACTION]: BroadcastChannelProcedureName.STOP_TRANSACTION,
- [ProcedureName.AUTHORIZE]: BroadcastChannelProcedureName.AUTHORIZE,
- [ProcedureName.STATUS_NOTIFICATION]: BroadcastChannelProcedureName.STATUS_NOTIFICATION,
- [ProcedureName.HEARTBEAT]: BroadcastChannelProcedureName.HEARTBEAT,
-};
-
export default class UIService001 extends AbstractUIService {
+ private static readonly ProcedureNameToBroadCastChannelProcedureNameMap: Omit<
+ Record<ProcedureName, BroadcastChannelProcedureName>,
+ 'startSimulator' | 'stopSimulator' | 'listChargingStations'
+ > = {
+ [ProcedureName.START_CHARGING_STATION]: BroadcastChannelProcedureName.START_CHARGING_STATION,
+ [ProcedureName.STOP_CHARGING_STATION]: BroadcastChannelProcedureName.STOP_CHARGING_STATION,
+ [ProcedureName.CLOSE_CONNECTION]: BroadcastChannelProcedureName.CLOSE_CONNECTION,
+ [ProcedureName.OPEN_CONNECTION]: BroadcastChannelProcedureName.OPEN_CONNECTION,
+ [ProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR]:
+ BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
+ [ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR]:
+ BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
+ [ProcedureName.START_TRANSACTION]: BroadcastChannelProcedureName.START_TRANSACTION,
+ [ProcedureName.STOP_TRANSACTION]: BroadcastChannelProcedureName.STOP_TRANSACTION,
+ [ProcedureName.AUTHORIZE]: BroadcastChannelProcedureName.AUTHORIZE,
+ [ProcedureName.STATUS_NOTIFICATION]: BroadcastChannelProcedureName.STATUS_NOTIFICATION,
+ [ProcedureName.HEARTBEAT]: BroadcastChannelProcedureName.HEARTBEAT,
+ [ProcedureName.METER_VALUES]: BroadcastChannelProcedureName.METER_VALUES,
+ };
+
constructor(uiServer: AbstractUIServer) {
super(uiServer, ProtocolVersion['0.0.1']);
this.requestHandlers.set(
ProcedureName.HEARTBEAT,
this.handleProtocolRequest.bind(this) as ProtocolRequestHandler
);
+ this.requestHandlers.set(
+ ProcedureName.METER_VALUES,
+ this.handleProtocolRequest.bind(this) as ProtocolRequestHandler
+ );
}
private handleProtocolRequest(
): void {
this.sendBroadcastChannelRequest(
uuid,
- ProcedureNameToBroadCastChannelProcedureNameMap[
+ UIService001.ProcedureNameToBroadCastChannelProcedureNameMap[
procedureName
] as BroadcastChannelProcedureName,
payload