OCPP20ResponseService,
type OCPPIncomingRequestService,
type OCPPRequestService,
- OCPPServiceUtils,
+ buildStatusNotificationRequest,
+ getMessageTypeString,
+ sendAndSetConnectorStatus,
} from './ocpp';
import { SharedLRUCache } from './SharedLRUCache';
import { BaseError, OCPPError } from '../exception';
await this.removeReservation(reservationFound, ReservationTerminationReason.REPLACE_EXISTING);
}
this.getConnectorStatus(reservation.connectorId)!.reservation = reservation;
- await OCPPServiceUtils.sendAndSetConnectorStatus(
+ await sendAndSetConnectorStatus(
this,
reservation.connectorId,
ConnectorStatusEnum.Reserved,
case ReservationTerminationReason.RESERVATION_CANCELED:
case ReservationTerminationReason.REPLACE_EXISTING:
case ReservationTerminationReason.EXPIRED:
- await OCPPServiceUtils.sendAndSetConnectorStatus(
+ await sendAndSetConnectorStatus(
this,
reservation.connectorId,
ConnectorStatusEnum.Available,
isRequest && PerformanceStatistics.endMeasure(commandName!, beginId!);
if (isNullOrUndefined(error)) {
logger.debug(
- `${this.logPrefix()} >> Buffered ${OCPPServiceUtils.getMessageTypeString(
+ `${this.logPrefix()} >> Buffered ${getMessageTypeString(
messageType,
- )} payload sent: ${message}`,
+ )} OCPP message sent '${JSON.stringify(message)}'`,
);
this.messageBuffer.delete(message);
+ } else {
+ logger.debug(
+ `${this.logPrefix()} >> Buffered ${getMessageTypeString(
+ messageType,
+ )} OCPP message '${JSON.stringify(message)}' send failed:`,
+ error,
+ );
}
});
}
}
throw new OCPPError(
ErrorType.PROTOCOL_ERROR,
- `Cached request for message id ${messageId} ${OCPPServiceUtils.getMessageTypeString(
+ `Cached request for message id ${messageId} ${getMessageTypeString(
messageType,
)} is not an array`,
undefined,
if (evseId > 0) {
for (const [connectorId, connectorStatus] of evseStatus.connectors) {
const connectorBootStatus = getBootConnectorStatus(this, connectorId, connectorStatus);
- await OCPPServiceUtils.sendAndSetConnectorStatus(
- this,
- connectorId,
- connectorBootStatus,
- evseId,
- );
+ await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus, evseId);
}
}
}
connectorId,
this.getConnectorStatus(connectorId)!,
);
- await OCPPServiceUtils.sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
+ await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
}
}
}
>(
this,
RequestCommand.STATUS_NOTIFICATION,
- OCPPServiceUtils.buildStatusNotificationRequest(
+ buildStatusNotificationRequest(
this,
connectorId,
ConnectorStatusEnum.Unavailable,
>(
this,
RequestCommand.STATUS_NOTIFICATION,
- OCPPServiceUtils.buildStatusNotificationRequest(
- this,
- connectorId,
- ConnectorStatusEnum.Unavailable,
- ),
+ buildStatusNotificationRequest(this, connectorId, ConnectorStatusEnum.Unavailable),
);
delete this.getConnectorStatus(connectorId)?.status;
}
min,
} from '../../utils';
+export const getMessageTypeString = (messageType: MessageType): string => {
+ switch (messageType) {
+ case MessageType.CALL_MESSAGE:
+ return 'request';
+ case MessageType.CALL_RESULT_MESSAGE:
+ return 'response';
+ case MessageType.CALL_ERROR_MESSAGE:
+ return 'error';
+ default:
+ return 'unknown';
+ }
+};
+
+export const buildStatusNotificationRequest = (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ status: ConnectorStatusEnum,
+ evseId?: number,
+): StatusNotificationRequest => {
+ switch (chargingStation.stationInfo?.ocppVersion) {
+ case OCPPVersion.VERSION_16:
+ return {
+ connectorId,
+ status,
+ errorCode: ChargePointErrorCode.NO_ERROR,
+ } as OCPP16StatusNotificationRequest;
+ case OCPPVersion.VERSION_20:
+ case OCPPVersion.VERSION_201:
+ return {
+ timestamp: new Date(),
+ connectorStatus: status,
+ connectorId,
+ evseId,
+ } as OCPP20StatusNotificationRequest;
+ default:
+ throw new BaseError('Cannot build status notification payload: OCPP version not supported');
+ }
+};
+
+export const isIdTagAuthorized = async (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ idTag: string,
+): Promise<boolean> => {
+ if (
+ !chargingStation.getLocalAuthListEnabled() &&
+ !chargingStation.stationInfo?.remoteAuthorization
+ ) {
+ logger.warn(
+ `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`,
+ );
+ }
+ if (
+ chargingStation.getLocalAuthListEnabled() === true &&
+ isIdTagLocalAuthorized(chargingStation, idTag)
+ ) {
+ const connectorStatus: ConnectorStatus = chargingStation.getConnectorStatus(connectorId)!;
+ connectorStatus.localAuthorizeIdTag = idTag;
+ connectorStatus.idTagLocalAuthorized = true;
+ return true;
+ } else if (chargingStation.stationInfo?.remoteAuthorization) {
+ return await isIdTagRemoteAuthorized(chargingStation, connectorId, idTag);
+ }
+ return false;
+};
+
+const isIdTagLocalAuthorized = (chargingStation: ChargingStation, idTag: string): boolean => {
+ return (
+ chargingStation.hasIdTags() === true &&
+ isNotEmptyString(
+ chargingStation.idTagsCache
+ .getIdTags(getIdTagsFile(chargingStation.stationInfo)!)
+ ?.find((tag) => tag === idTag),
+ )
+ );
+};
+
+const isIdTagRemoteAuthorized = async (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ idTag: string,
+): Promise<boolean> => {
+ chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag;
+ return (
+ (
+ await chargingStation.ocppRequestService.requestHandler<AuthorizeRequest, AuthorizeResponse>(
+ chargingStation,
+ RequestCommand.AUTHORIZE,
+ {
+ idTag,
+ },
+ )
+ )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
+ );
+};
+
+export const sendAndSetConnectorStatus = async (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ status: ConnectorStatusEnum,
+ evseId?: number,
+ options?: { send: boolean },
+): Promise<void> => {
+ options = { send: true, ...options };
+ if (options.send) {
+ checkConnectorStatusTransition(chargingStation, connectorId, status);
+ await chargingStation.ocppRequestService.requestHandler<
+ StatusNotificationRequest,
+ StatusNotificationResponse
+ >(
+ chargingStation,
+ RequestCommand.STATUS_NOTIFICATION,
+ buildStatusNotificationRequest(chargingStation, connectorId, status, evseId),
+ );
+ }
+ chargingStation.getConnectorStatus(connectorId)!.status = status;
+ chargingStation.emit(ChargingStationEvents.connectorStatusChanged, {
+ connectorId,
+ ...chargingStation.getConnectorStatus(connectorId),
+ });
+};
+
+const checkConnectorStatusTransition = (
+ chargingStation: ChargingStation,
+ connectorId: number,
+ status: ConnectorStatusEnum,
+): boolean => {
+ const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status;
+ let transitionAllowed = false;
+ switch (chargingStation.stationInfo?.ocppVersion) {
+ case OCPPVersion.VERSION_16:
+ if (
+ (connectorId === 0 &&
+ OCPP16Constants.ChargePointStatusChargingStationTransitions.findIndex(
+ (transition) => transition.from === fromStatus && transition.to === status,
+ ) !== -1) ||
+ (connectorId > 0 &&
+ OCPP16Constants.ChargePointStatusConnectorTransitions.findIndex(
+ (transition) => transition.from === fromStatus && transition.to === status,
+ ) !== -1)
+ ) {
+ transitionAllowed = true;
+ }
+ break;
+ case OCPPVersion.VERSION_20:
+ case OCPPVersion.VERSION_201:
+ if (
+ (connectorId === 0 &&
+ OCPP20Constants.ChargingStationStatusTransitions.findIndex(
+ (transition) => transition.from === fromStatus && transition.to === status,
+ ) !== -1) ||
+ (connectorId > 0 &&
+ OCPP20Constants.ConnectorStatusTransitions.findIndex(
+ (transition) => transition.from === fromStatus && transition.to === status,
+ ) !== -1)
+ ) {
+ transitionAllowed = true;
+ }
+ break;
+ default:
+ throw new BaseError(
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+ `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
+ );
+ }
+ if (transitionAllowed === false) {
+ logger.warn(
+ `${chargingStation.logPrefix()} OCPP ${chargingStation.stationInfo
+ ?.ocppVersion} connector id ${connectorId} status transition from '${
+ chargingStation.getConnectorStatus(connectorId)!.status
+ }' to '${status}' is not allowed`,
+ );
+ }
+ return transitionAllowed;
+};
+
export class OCPPServiceUtils {
+ public static getMessageTypeString = getMessageTypeString;
+ public static sendAndSetConnectorStatus = sendAndSetConnectorStatus;
+ public static isIdTagAuthorized = isIdTagAuthorized;
+
protected constructor() {
// This is intentional
}
return ErrorType.FORMAT_VIOLATION;
}
- public static getMessageTypeString(messageType: MessageType): string {
- switch (messageType) {
- case MessageType.CALL_MESSAGE:
- return 'request';
- case MessageType.CALL_RESULT_MESSAGE:
- return 'response';
- case MessageType.CALL_ERROR_MESSAGE:
- return 'error';
- default:
- return 'unknown';
- }
- }
-
public static isRequestCommandSupported(
chargingStation: ChargingStation,
command: RequestCommand,
}
}
- public static buildStatusNotificationRequest(
- chargingStation: ChargingStation,
- connectorId: number,
- status: ConnectorStatusEnum,
- evseId?: number,
- ): StatusNotificationRequest {
- switch (chargingStation.stationInfo?.ocppVersion) {
- case OCPPVersion.VERSION_16:
- return {
- connectorId,
- status,
- errorCode: ChargePointErrorCode.NO_ERROR,
- } as OCPP16StatusNotificationRequest;
- case OCPPVersion.VERSION_20:
- case OCPPVersion.VERSION_201:
- return {
- timestamp: new Date(),
- connectorStatus: status,
- connectorId,
- evseId,
- } as OCPP20StatusNotificationRequest;
- default:
- throw new BaseError('Cannot build status notification payload: OCPP version not supported');
- }
- }
-
public static startHeartbeatInterval(chargingStation: ChargingStation, interval: number): void {
if (chargingStation.heartbeatSetInterval === undefined) {
chargingStation.startHeartbeat();
}
}
- public static async sendAndSetConnectorStatus(
- chargingStation: ChargingStation,
- connectorId: number,
- status: ConnectorStatusEnum,
- evseId?: number,
- options?: { send: boolean },
- ) {
- options = { send: true, ...options };
- if (options.send) {
- OCPPServiceUtils.checkConnectorStatusTransition(chargingStation, connectorId, status);
- await chargingStation.ocppRequestService.requestHandler<
- StatusNotificationRequest,
- StatusNotificationResponse
- >(
- chargingStation,
- RequestCommand.STATUS_NOTIFICATION,
- OCPPServiceUtils.buildStatusNotificationRequest(
- chargingStation,
- connectorId,
- status,
- evseId,
- ),
- );
- }
- chargingStation.getConnectorStatus(connectorId)!.status = status;
- chargingStation.emit(ChargingStationEvents.connectorStatusChanged, {
- connectorId,
- ...chargingStation.getConnectorStatus(connectorId),
- });
- }
-
- public static async isIdTagAuthorized(
- chargingStation: ChargingStation,
- connectorId: number,
- idTag: string,
- ): Promise<boolean> {
- if (
- !chargingStation.getLocalAuthListEnabled() &&
- !chargingStation.stationInfo?.remoteAuthorization
- ) {
- logger.warn(
- `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`,
- );
- }
- if (
- chargingStation.getLocalAuthListEnabled() === true &&
- OCPPServiceUtils.isIdTagLocalAuthorized(chargingStation, idTag)
- ) {
- const connectorStatus: ConnectorStatus = chargingStation.getConnectorStatus(connectorId)!;
- connectorStatus.localAuthorizeIdTag = idTag;
- connectorStatus.idTagLocalAuthorized = true;
- return true;
- } else if (chargingStation.stationInfo?.remoteAuthorization) {
- return await OCPPServiceUtils.isIdTagRemoteAuthorized(chargingStation, connectorId, idTag);
- }
- return false;
- }
-
- protected static checkConnectorStatusTransition(
- chargingStation: ChargingStation,
- connectorId: number,
- status: ConnectorStatusEnum,
- ): boolean {
- const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status;
- let transitionAllowed = false;
- switch (chargingStation.stationInfo?.ocppVersion) {
- case OCPPVersion.VERSION_16:
- if (
- (connectorId === 0 &&
- OCPP16Constants.ChargePointStatusChargingStationTransitions.findIndex(
- (transition) => transition.from === fromStatus && transition.to === status,
- ) !== -1) ||
- (connectorId > 0 &&
- OCPP16Constants.ChargePointStatusConnectorTransitions.findIndex(
- (transition) => transition.from === fromStatus && transition.to === status,
- ) !== -1)
- ) {
- transitionAllowed = true;
- }
- break;
- case OCPPVersion.VERSION_20:
- case OCPPVersion.VERSION_201:
- if (
- (connectorId === 0 &&
- OCPP20Constants.ChargingStationStatusTransitions.findIndex(
- (transition) => transition.from === fromStatus && transition.to === status,
- ) !== -1) ||
- (connectorId > 0 &&
- OCPP20Constants.ConnectorStatusTransitions.findIndex(
- (transition) => transition.from === fromStatus && transition.to === status,
- ) !== -1)
- ) {
- transitionAllowed = true;
- }
- break;
- default:
- throw new BaseError(
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
- );
- }
- if (transitionAllowed === false) {
- logger.warn(
- `${chargingStation.logPrefix()} OCPP ${chargingStation.stationInfo
- ?.ocppVersion} connector id ${connectorId} status transition from '${
- chargingStation.getConnectorStatus(connectorId)!.status
- }' to '${status}' is not allowed`,
- );
- }
- return transitionAllowed;
- }
-
protected static parseJsonSchemaFile<T extends JsonType>(
relativePath: string,
ocppVersion: OCPPVersion,
return (!isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier!;
}
- private static isIdTagLocalAuthorized(chargingStation: ChargingStation, idTag: string): boolean {
- return (
- chargingStation.hasIdTags() === true &&
- isNotEmptyString(
- chargingStation.idTagsCache
- .getIdTags(getIdTagsFile(chargingStation.stationInfo)!)
- ?.find((tag) => tag === idTag),
- )
- );
- }
-
- private static async isIdTagRemoteAuthorized(
- chargingStation: ChargingStation,
- connectorId: number,
- idTag: string,
- ): Promise<boolean> {
- chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag;
- return (
- (
- await chargingStation.ocppRequestService.requestHandler<
- AuthorizeRequest,
- AuthorizeResponse
- >(chargingStation, RequestCommand.AUTHORIZE, {
- idTag,
- })
- )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
- );
- }
-
private static logPrefix = (
ocppVersion: OCPPVersion,
moduleName?: string,