import { FileType } from '../types/FileType';
import type { JsonType } from '../types/JsonType';
import { ChargePointErrorCode } from '../types/ocpp/ChargePointErrorCode';
-import { ChargePointStatus } from '../types/ocpp/ChargePointStatus';
import { ChargingProfile, ChargingRateUnitType } from '../types/ocpp/ChargingProfile';
import {
ConnectorPhaseRotation,
SupportedFeatureProfiles,
VendorDefaultParametersKey,
} from '../types/ocpp/Configuration';
+import { ConnectorStatusEnum } from '../types/ocpp/ConnectorStatusEnum';
import { ErrorType } from '../types/ocpp/ErrorType';
import { MessageType } from '../types/ocpp/MessageType';
import { MeterValue, MeterValueMeasurand } from '../types/ocpp/MeterValues';
import OCPP20ResponseService from './ocpp/2.0/OCPP20ResponseService';
import type OCPPIncomingRequestService from './ocpp/OCPPIncomingRequestService';
import type OCPPRequestService from './ocpp/OCPPRequestService';
+import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
import SharedLRUCache from './SharedLRUCache';
export default class ChargingStation {
this.startHeartbeat();
// Initialize connectors status
for (const connectorId of this.connectors.keys()) {
- let chargePointStatus: ChargePointStatus;
+ let connectorStatus: ConnectorStatusEnum;
if (connectorId === 0) {
continue;
} else if (
(this.isChargingStationAvailable() === false ||
this.isConnectorAvailable(connectorId) === false)
) {
- chargePointStatus = ChargePointStatus.UNAVAILABLE;
+ connectorStatus = ConnectorStatusEnum.UNAVAILABLE;
} else if (
!this.getConnectorStatus(connectorId)?.status &&
this.getConnectorStatus(connectorId)?.bootStatus
) {
// Set boot status in template at startup
- chargePointStatus = this.getConnectorStatus(connectorId).bootStatus;
+ connectorStatus = this.getConnectorStatus(connectorId).bootStatus;
} else if (this.getConnectorStatus(connectorId)?.status) {
// Set previous status at startup
- chargePointStatus = this.getConnectorStatus(connectorId).status;
+ connectorStatus = this.getConnectorStatus(connectorId).status;
} else {
// Set default status
- chargePointStatus = ChargePointStatus.AVAILABLE;
+ connectorStatus = ConnectorStatusEnum.AVAILABLE;
}
await this.ocppRequestService.requestHandler<
StatusNotificationRequest,
StatusNotificationResponse
- >(this, RequestCommand.STATUS_NOTIFICATION, {
- connectorId,
- status: chargePointStatus,
- errorCode: ChargePointErrorCode.NO_ERROR,
- });
- this.getConnectorStatus(connectorId).status = chargePointStatus;
+ >(
+ this,
+ RequestCommand.STATUS_NOTIFICATION,
+ OCPPServiceUtils.buildStatusNotificationRequest(this, connectorId, connectorStatus)
+ );
+ this.getConnectorStatus(connectorId).status = connectorStatus;
}
if (this.stationInfo?.firmwareStatus === FirmwareStatus.Installing) {
await this.ocppRequestService.requestHandler<
await this.ocppRequestService.requestHandler<
StatusNotificationRequest,
StatusNotificationResponse
- >(this, RequestCommand.STATUS_NOTIFICATION, {
- connectorId,
- status: ChargePointStatus.UNAVAILABLE,
- errorCode: ChargePointErrorCode.NO_ERROR,
- });
+ >(
+ this,
+ RequestCommand.STATUS_NOTIFICATION,
+ OCPPServiceUtils.buildStatusNotificationRequest(
+ this,
+ connectorId,
+ ConnectorStatusEnum.UNAVAILABLE
+ )
+ );
this.getConnectorStatus(connectorId).status = null;
}
}
type OCPP20BootNotificationRequest,
type OCPP20HeartbeatRequest,
OCPP20RequestCommand,
+ type OCPP20StatusNotificationRequest,
} from '../../../types/ocpp/2.0/Requests';
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
)
) as JSONSchemaType<OCPP20HeartbeatRequest>,
],
+ [
+ OCPP20RequestCommand.STATUS_NOTIFICATION,
+ JSON.parse(
+ fs.readFileSync(
+ path.resolve(
+ path.dirname(fileURLToPath(import.meta.url)),
+ '../../../assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json'
+ ),
+ 'utf8'
+ )
+ ) as JSONSchemaType<OCPP20StatusNotificationRequest>,
+ ],
]);
this.buildRequestPayload.bind(this);
}
} as unknown as Request;
case OCPP20RequestCommand.HEARTBEAT:
return {} as unknown as Request;
+ case OCPP20RequestCommand.STATUS_NOTIFICATION:
+ return {
+ timestamp: commandParams?.timestamp,
+ connectorStatus: commandParams?.connectorStatus,
+ evseId: commandParams?.evseId,
+ connectorId: commandParams?.connectorId,
+ } as unknown as Request;
default:
// OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
throw new OCPPError(
OCPP20BootNotificationResponse,
OCPP20ClearCacheResponse,
OCPP20HeartbeatResponse,
+ OCPP20StatusNotificationResponse,
} from '../../../types/ocpp/2.0/Responses';
import { ErrorType } from '../../../types/ocpp/ErrorType';
import { OCPPVersion } from '../../../types/ocpp/OCPPVersion';
this.responseHandlers = new Map<OCPP20RequestCommand, ResponseHandler>([
[OCPP20RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
[OCPP20RequestCommand.HEARTBEAT, this.emptyResponseHandler.bind(this)],
+ [OCPP20RequestCommand.STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
]);
this.jsonSchemas = new Map<OCPP20RequestCommand, JSONSchemaType<JsonObject>>([
[
)
) as JSONSchemaType<OCPP20HeartbeatResponse>,
],
+ [
+ OCPP20RequestCommand.STATUS_NOTIFICATION,
+ JSON.parse(
+ fs.readFileSync(
+ path.resolve(
+ path.dirname(fileURLToPath(import.meta.url)),
+ '../../../assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json'
+ ),
+ 'utf8'
+ )
+ ) as JSONSchemaType<OCPP20StatusNotificationResponse>,
+ ],
]);
this.jsonIncomingRequestResponseSchemas = new Map([
[
import BaseError from '../../exception/BaseError';
import type { JsonObject, JsonType } from '../../types/JsonType';
import type { SampledValueTemplate } from '../../types/MeasurandPerPhaseSampledValueTemplates';
+import type { OCPP16StatusNotificationRequest } from '../../types/ocpp/1.6/Requests';
+import type { OCPP20StatusNotificationRequest } from '../../types/ocpp/2.0/Requests';
+import { ChargePointErrorCode } from '../../types/ocpp/ChargePointErrorCode';
import { StandardParametersKey } from '../../types/ocpp/Configuration';
+import type { ConnectorStatusEnum } from '../../types/ocpp/ConnectorStatusEnum';
import { ErrorType } from '../../types/ocpp/ErrorType';
import { MeterValueMeasurand, type MeterValuePhase } from '../../types/ocpp/MeterValues';
-import { IncomingRequestCommand, MessageTrigger, RequestCommand } from '../../types/ocpp/Requests';
+import { OCPPVersion } from '../../types/ocpp/OCPPVersion';
+import {
+ IncomingRequestCommand,
+ MessageTrigger,
+ RequestCommand,
+ type StatusNotificationRequest,
+} from '../../types/ocpp/Requests';
import Constants from '../../utils/Constants';
import logger from '../../utils/Logger';
import Utils from '../../utils/Utils';
}
}
+ public static buildStatusNotificationRequest(
+ chargingStation: ChargingStation,
+ connectorId: number,
+ status: ConnectorStatusEnum
+ ): 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: connectorId,
+ } as OCPP20StatusNotificationRequest;
+ }
+ }
+
protected static getSampledValueTemplate(
chargingStation: ChargingStation,
connectorId: number,
import type { SampledValueTemplate } from './MeasurandPerPhaseSampledValueTemplates';
-import type { ChargePointStatus } from './ocpp/ChargePointStatus';
import type { ChargingProfile } from './ocpp/ChargingProfile';
+import type { ConnectorStatusEnum } from './ocpp/ConnectorStatusEnum';
import type { MeterValue } from './ocpp/MeterValues';
import type { AvailabilityType } from './ocpp/Requests';
export type ConnectorStatus = {
availability: AvailabilityType;
- bootStatus?: ChargePointStatus;
- status?: ChargePointStatus;
+ bootStatus?: ConnectorStatusEnum;
+ status?: ConnectorStatusEnum;
MeterValues: SampledValueTemplate[];
authorizeIdTag?: string;
idTagAuthorized?: boolean;
export enum OCPP20RequestCommand {
BOOT_NOTIFICATION = 'BootNotification',
HEARTBEAT = 'Heartbeat',
+ STATUS_NOTIFICATION = 'StatusNotification',
}
export enum OCPP20IncomingRequestCommand {
export type OCPP20HeartbeatRequest = EmptyObject;
export type OCPP20ClearCacheRequest = EmptyObject;
+
+export enum OCPP20ConnectorStatusEnumType {
+ AVAILABLE = 'Available',
+ OCCUPIED = 'Occupied',
+ RESERVED = 'Reserved',
+ UNAVAILABLE = 'Unavailable',
+ FAULTED = 'Faulted',
+}
+
+export type OCPP20StatusNotificationRequest = {
+ timestamp: Date;
+ connectorStatus: OCPP20ConnectorStatusEnumType;
+ evseId: number;
+ connectorId: number;
+};
+import type { EmptyObject } from '../../EmptyObject';
import type { JsonObject } from '../../JsonType';
import type { DefaultStatus, RegistrationStatusEnumType } from '../Responses';
status: DefaultStatus;
statusInfo?: StatusInfoType;
} & JsonObject;
+
+export type OCPP20StatusNotificationResponse = EmptyObject;
+++ /dev/null
-import { OCPP16ChargePointStatus } from './1.6/ChargePointStatus';
-
-export const ChargePointStatus = {
- ...OCPP16ChargePointStatus,
-} as const;
-export type ChargePointStatus = OCPP16ChargePointStatus;
import {
- OCPP16ChargingProfile,
+ type OCPP16ChargingProfile,
OCPP16ChargingRateUnitType,
- OCPP16ChargingSchedulePeriod,
+ type OCPP16ChargingSchedulePeriod,
} from './1.6/ChargingProfile';
export type ChargingProfile = OCPP16ChargingProfile;
--- /dev/null
+import { OCPP16ChargePointStatus } from './1.6/ChargePointStatus';
+import { OCPP20ConnectorStatusEnumType } from './2.0/Requests';
+
+export const ConnectorStatusEnum = {
+ ...OCPP16ChargePointStatus,
+ ...OCPP20ConnectorStatusEnumType,
+} as const;
+export type ConnectorStatusEnum = OCPP16ChargePointStatus | OCPP20ConnectorStatusEnumType;
type OCPP20BootNotificationRequest,
OCPP20IncomingRequestCommand,
OCPP20RequestCommand,
+ type OCPP20StatusNotificationRequest,
} from './2.0/Requests';
import type { MessageType } from './MessageType';
export type HeartbeatRequest = OCPP16HeartbeatRequest;
-export type StatusNotificationRequest = OCPP16StatusNotificationRequest;
+export type StatusNotificationRequest =
+ | OCPP16StatusNotificationRequest
+ | OCPP20StatusNotificationRequest;
export type MeterValuesRequest = OCPP16MeterValuesRequest;
OCPP16TriggerMessageStatus,
OCPP16UnlockStatus,
} from './1.6/Responses';
-import type { OCPP20BootNotificationResponse, OCPP20ClearCacheResponse } from './2.0/Responses';
+import type {
+ OCPP20BootNotificationResponse,
+ OCPP20ClearCacheResponse,
+ OCPP20StatusNotificationResponse,
+} from './2.0/Responses';
import type { ErrorType } from './ErrorType';
import type { MessageType } from './MessageType';
export type ClearCacheResponse = DefaultResponse | OCPP20ClearCacheResponse;
-export type StatusNotificationResponse = OCPP16StatusNotificationResponse;
+export type StatusNotificationResponse =
+ | OCPP16StatusNotificationResponse
+ | OCPP20StatusNotificationResponse;
export type MeterValuesResponse = OCPP16MeterValuesResponse;