`PDU`: {
`status`: 'success' | 'failure',
`hashIdsSucceeded`: charging station unique identifier strings array,
- `hashIdsFailed`: charging station unique identifier strings array (optional)
+ `hashIdsFailed`: charging station unique identifier strings array (optional),
+ `responsesFailed`: failed responses payload array (optional)
}
###### Stop Transaction
`hashIdsFailed`: charging station unique identifier strings array (optional)
}
+###### Stop Automatic Transaction Generator
+
+- Request:
+ `ProcedureName`: 'StatusNotification'
+ `PDU`: {
+ `hashIds`: charging station unique identifier strings array (optional, default: all charging stations),
+ `connectorId`: connector id integer
+ }
+
+- Response:
+ `PDU`: {
+ `status`: 'success' | 'failure',
+ `hashIdsSucceeded`: charging station unique identifier strings array,
+ `hashIdsFailed`: charging station unique identifier strings array (optional)
+ `responsesFailed`: failed responses payload array (optional)
+ }
+
## Support, Feedback, Contributing
This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/SAP/e-mobility-charging-stations-simulator/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).
import BaseError from '../exception/BaseError';
-import { RequestCommand } from '../types/ocpp/Requests';
+import type OCPPError from '../exception/OCPPError';
+import { RequestCommand, type StatusNotificationRequest } from '../types/ocpp/Requests';
+import type { StatusNotificationResponse } from '../types/ocpp/Responses';
import {
AuthorizationStatus,
StartTransactionRequest,
} from '../types/WorkerBroadcastChannel';
import { ResponseStatus } from '../ui/web/src/types/UIProtocol';
import logger from '../utils/Logger';
+import Utils from '../utils/Utils';
import type ChargingStation from './ChargingStation';
import WorkerBroadcastChannel from './WorkerBroadcastChannel';
const moduleName = 'ChargingStationWorkerBroadcastChannel';
-type CommandResponse = StartTransactionResponse | StopTransactionResponse;
+type CommandResponse =
+ | StartTransactionResponse
+ | StopTransactionResponse
+ | StatusNotificationResponse;
export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChannel {
private readonly chargingStation: ChargingStation;
commandResponse,
errorMessage: (error as Error).message,
errorStack: (error as Error).stack,
+ errorDetails: (error as OCPPError).details,
};
}
this.sendResponse([uuid, responsePayload]);
case BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR:
this.chargingStation.stopAutomaticTransactionGenerator(requestPayload.connectorIds);
break;
+ case BroadcastChannelProcedureName.STATUS_NOTIFICATION:
+ return this.chargingStation.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(this.chargingStation, RequestCommand.STATUS_NOTIFICATION, {
+ connectorId: requestPayload.connectorId,
+ errorCode: requestPayload.errorCode,
+ status: requestPayload.status,
+ ...(requestPayload.info && { info: requestPayload.info }),
+ ...(requestPayload.timestamp && { timestamp: requestPayload.timestamp }),
+ ...(requestPayload.vendorId && { vendorId: requestPayload.vendorId }),
+ ...(requestPayload.vendorErrorCode && {
+ vendorErrorCode: requestPayload.vendorErrorCode,
+ }),
+ });
default:
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
}
private commandResponseToResponseStatus(commandResponse: CommandResponse): ResponseStatus {
- if (commandResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
+ if (
+ Utils.isEmptyObject(commandResponse) ||
+ commandResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
+ ) {
return ResponseStatus.SUCCESS;
}
return ResponseStatus.FAILURE;
ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
this.handleStopAutomaticTransactionGenerator.bind(this) as ProtocolRequestHandler
);
+ this.requestHandlers.set(
+ ProcedureName.STATUS_NOTIFICATION,
+ this.handleStatusNotification.bind(this) as ProtocolRequestHandler
+ );
}
private handleStartChargingStation(uuid: string, payload: RequestPayload): void {
payload
);
}
+
+ private handleStatusNotification(uuid: string, payload: RequestPayload): void {
+ this.sendBroadcastChannelRequest(
+ uuid,
+ BroadcastChannelProcedureName.STATUS_NOTIFICATION,
+ payload
+ );
+ }
}
STOP_TRANSACTION = 'stopTransaction',
START_AUTOMATIC_TRANSACTION_GENERATOR = 'startAutomaticTransactionGenerator',
STOP_AUTOMATIC_TRANSACTION_GENERATOR = 'stopAutomaticTransactionGenerator',
+ STATUS_NOTIFICATION = 'statusNotification',
}
export interface RequestPayload extends JsonObject {
STOP_TRANSACTION = 'stopTransaction',
START_AUTOMATIC_TRANSACTION_GENERATOR = 'startAutomaticTransactionGenerator',
STOP_AUTOMATIC_TRANSACTION_GENERATOR = 'stopAutomaticTransactionGenerator',
+ STATUS_NOTIFICATION = 'statusNotification',
}
export interface BroadcastChannelRequestPayload extends RequestPayload {
idTag?: string;
}
-export interface BroadcastChannelResponsePayload extends ResponsePayload {
+export interface BroadcastChannelResponsePayload
+ extends Omit<ResponsePayload, 'hashIdsSucceeded' | 'hashIdsFailed' | 'responsesFailed'> {
hashId: string;
}
export interface OCPP16StatusNotificationRequest extends JsonObject {
connectorId: number;
errorCode: OCPP16ChargePointErrorCode;
- info?: string;
status: OCPP16ChargePointStatus;
+ info?: string;
timestamp?: string;
vendorId?: string;
vendorErrorCode?: string;