type Response,
StandardParametersKey,
type Status,
- type StatusNotificationRequest,
type StopTransactionReason,
SupervisionUrlDistribution,
SupportedFeatureProfiles,
{
connectorId: reservation.connectorId,
status: ConnectorStatusEnum.Reserved,
- } as unknown as StatusNotificationRequest,
+ },
{ send: reservation.connectorId !== 0 }
)
}
{
connectorId: reservation.connectorId,
status: ConnectorStatusEnum.Available,
- } as unknown as StatusNotificationRequest,
+ },
{ send: reservation.connectorId !== 0 }
)
delete connectorStatus.reservation
connectorId,
...(evseId != null && { evseId }),
status: getBootConnectorStatus(this, connectorId, connectorStatus),
- } as unknown as StatusNotificationRequest)
+ })
}
if (this.stationInfo?.firmwareStatus === FirmwareStatus.Installing) {
await this.ocppRequestService.requestHandler<
connectorId,
...(evseId != null && { evseId }),
status: ConnectorStatusEnum.Unavailable,
- } as unknown as StatusNotificationRequest)
+ })
delete connectorStatus.status
}
}
ResponseStatus,
StandardParametersKey,
type StartTransactionResponse,
- type StatusNotificationRequest,
+ type StatusNotificationOptions,
type StopTransactionRequest,
type StopTransactionResponse,
} from '../../types/index.js'
`${this.chargingStation.logPrefix()} ${moduleName}.handleStatusNotification: 'connectorId' field is required`
)
}
- const payload = requestPayload as Record<string, unknown>
- if (payload.connectorStatus == null && payload.status == null) {
+ const options = requestPayload as StatusNotificationOptions
+ if (options.connectorStatus == null && options.status == null) {
throw new BaseError(
`${this.chargingStation.logPrefix()} ${moduleName}.handleStatusNotification: 'connectorStatus' or 'status' field is required`
)
}
- await sendAndSetConnectorStatus(
- this.chargingStation,
- requestPayload as unknown as StatusNotificationRequest
- )
+ await sendAndSetConnectorStatus(this.chargingStation, options)
}
private async handleStopTransaction (
OCPP16StandardParametersKey,
type OCPP16StartTransactionRequest,
type OCPP16StartTransactionResponse,
- type OCPP16StatusNotificationRequest,
type OCPP16StatusNotificationResponse,
OCPP16StopTransactionReason,
OCPP16SupportedFeatureProfiles,
type ResetRequest,
type SetChargingProfileRequest,
type SetChargingProfileResponse,
+ type StatusNotificationOptions,
type UnlockConnectorRequest,
type UnlockConnectorResponse,
} from '../../../types/index.js'
case OCPP16MessageTrigger.StatusNotification:
if (connectorId != null) {
chargingStation.ocppRequestService
- .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
+ .requestHandler<StatusNotificationOptions, OCPP16StatusNotificationResponse>(
chargingStation,
OCPP16RequestCommand.STATUS_NOTIFICATION,
{
connectorId,
status: chargingStation.getConnectorStatus(connectorId)
?.status as OCPP16ChargePointStatus,
- } as unknown as OCPP16StatusNotificationRequest,
+ },
{
triggerMessage: true,
}
} else {
for (const { connectorId, connectorStatus } of chargingStation.iterateConnectors()) {
chargingStation.ocppRequestService
- .requestHandler<
- OCPP16StatusNotificationRequest,
- OCPP16StatusNotificationResponse
- >(
+ .requestHandler<StatusNotificationOptions, OCPP16StatusNotificationResponse>(
chargingStation,
OCPP16RequestCommand.STATUS_NOTIFICATION,
{
connectorId,
status: connectorStatus.status as OCPP16ChargePointStatus,
- } as unknown as OCPP16StatusNotificationRequest,
+ },
{
triggerMessage: true,
}
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: chargePointStatus,
- } as OCPP16StatusNotificationRequest)
+ })
return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
}
return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Available,
- } as OCPP16StatusNotificationRequest)
+ })
chargingStation.unlockConnector(connectorId)
return OCPP16Constants.OCPP_RESPONSE_UNLOCKED
}
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Unavailable,
- } as OCPP16StatusNotificationRequest)
+ })
}
}
await chargingStation.ocppRequestService.requestHandler<
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Unavailable,
- } as OCPP16StatusNotificationRequest)
+ })
}
}
transactionsStarted = false
const requestPayload =
params?.rawPayload === true
? (commandParams as RequestType)
- : this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams)
+ : this.buildRequestPayload(chargingStation, commandName, commandParams)
const messageId = generateUUID()
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
await sendAndSetConnectorStatus(chargingStation, {
connectorId: (commandParams as OCPP16StartTransactionRequest).connectorId,
status: OCPP16ChargePointStatus.Preparing,
- } as OCPP16StatusNotificationRequest)
+ })
break
}
const response = (await this.sendMessage(
* @param commandParams - Optional parameters provided by the caller for payload construction
* @returns The fully constructed and validated request payload ready for transmission
*/
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- private buildRequestPayload<Request extends JsonType>(
+ private buildRequestPayload (
chargingStation: ChargingStation,
commandName: OCPP16RequestCommand,
commandParams?: JsonType
- ): Request {
+ ): JsonType {
let connectorId: number | undefined
let energyActiveImportRegister: number
logger.debug(
case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
case OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION:
case OCPP16RequestCommand.METER_VALUES:
- return commandParams as unknown as Request
+ return commandParams ?? OCPP16Constants.OCPP_REQUEST_EMPTY
case OCPP16RequestCommand.HEARTBEAT:
- return OCPP16Constants.OCPP_REQUEST_EMPTY as unknown as Request
+ return OCPP16Constants.OCPP_REQUEST_EMPTY
}
assertIsJsonObject(
commandParams,
return {
idTag: OCPP16Constants.OCPP_DEFAULT_IDTAG,
...params,
- } as unknown as Request
+ }
case OCPP16RequestCommand.START_TRANSACTION:
return {
idTag: OCPP16Constants.OCPP_DEFAULT_IDTAG,
)?.reservationId,
}),
...params,
- } as unknown as Request
+ }
case OCPP16RequestCommand.STATUS_NOTIFICATION:
return OCPP16ServiceUtils.buildStatusNotificationRequest({
errorCode: ChargePointErrorCode.NO_ERROR,
...params,
- } as OCPP16StatusNotificationRequest) as unknown as Request
+ } as OCPP16StatusNotificationRequest)
case OCPP16RequestCommand.STOP_TRANSACTION:
;(chargingStation.stationInfo?.transactionDataMeterValues === true ||
OCPP16ServiceUtils.isSigningEnabled(chargingStation)) &&
timestamp: new Date(),
...(transactionData != null && { transactionData }),
...params,
- } as unknown as Request
+ }
}
default: {
// OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
OCPP16StandardParametersKey,
type OCPP16StartTransactionRequest,
type OCPP16StartTransactionResponse,
- type OCPP16StatusNotificationRequest,
type OCPP16StopTransactionRequest,
type OCPP16StopTransactionResponse,
OCPPVersion,
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Charging,
- } as OCPP16StatusNotificationRequest)
+ })
logger.info(
`${chargingStation.logPrefix()} ${moduleName}.handleResponseStartTransaction: Transaction with id ${payload.transactionId.toString()} STARTED on ${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
await sendAndSetConnectorStatus(chargingStation, {
connectorId: transactionConnectorId,
status: OCPP16ChargePointStatus.Finishing,
- } as OCPP16StatusNotificationRequest)
+ })
}
OCPP16ServiceUtils.stopUpdatedMeterValues(chargingStation, transactionConnectorId)
if (transactionConnectorStatus != null) {
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: chargePointStatus,
- } as OCPP16StatusNotificationRequest)
+ })
}
responses.push(response)
}
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Finishing,
- } as OCPP16StatusNotificationRequest)
+ })
const stopResponse = await OCPP16ServiceUtils.stopTransactionOnConnector(
chargingStation,
connectorId,
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: OCPP16ChargePointStatus.Finishing,
- } as OCPP16StatusNotificationRequest)
+ })
}
const rawTransactionId = chargingStation.getConnectorStatus(connectorId)?.transactionId
const transactionId = rawTransactionId != null ? convertToInt(rawTransactionId) : undefined
type OCPP20SetNetworkProfileResponse,
type OCPP20SetVariablesRequest,
type OCPP20SetVariablesResponse,
- type OCPP20StatusNotificationRequest,
type OCPP20StatusNotificationResponse,
OCPP20TransactionEventEnumType,
type OCPP20TriggerMessageRequest,
ResetStatusEnumType,
SetNetworkProfileStatusEnumType,
SetVariableStatusEnumType,
+ type StatusNotificationOptions,
StopTransactionReason,
TriggerMessageStatusEnumType,
UnlockStatusEnumType,
} from './OCPP20CertificateManager.js'
import { OCPP20CertSigningRetryManager } from './OCPP20CertSigningRetryManager.js'
import { OCPP20Constants } from './OCPP20Constants.js'
-import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
+import { isOCPP20ConnectorStatus, OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
import { OCPP20VariableManager } from './OCPP20VariableManager.js'
import { getVariableMetadata, VARIABLE_REGISTRY } from './OCPP20VariableRegistry.js'
// device capability declarations with no spec-defined ceiling.
const MAX_ITEMS_PER_REPORT_MESSAGE = 100 as const
+// V2GCertificateChain has no InstallCertificateUse counterpart, so it collapses onto V2GRootCertificate.
+const getCertificateIdUseToInstallCertificateUse: Readonly<
+ Record<GetCertificateIdUseEnumType, InstallCertificateUseEnumType>
+> = Object.freeze({
+ [GetCertificateIdUseEnumType.CSMSRootCertificate]:
+ InstallCertificateUseEnumType.CSMSRootCertificate,
+ [GetCertificateIdUseEnumType.ManufacturerRootCertificate]:
+ InstallCertificateUseEnumType.ManufacturerRootCertificate,
+ [GetCertificateIdUseEnumType.MORootCertificate]: InstallCertificateUseEnumType.MORootCertificate,
+ [GetCertificateIdUseEnumType.V2GCertificateChain]:
+ InstallCertificateUseEnumType.V2GRootCertificate,
+ [GetCertificateIdUseEnumType.V2GRootCertificate]:
+ InstallCertificateUseEnumType.V2GRootCertificate,
+})
+
interface StationInfoReportField {
property: 'chargePointModel' | 'chargePointSerialNumber' | 'chargePointVendor' | 'firmwareVersion'
variable: OCPP20DeviceInfoVariableName
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: resolvedStatus,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.handleConnectorChangeAvailability: Error sending status notification for connector ${connectorId.toString()}:`,
error
}
try {
- const filterTypes = certificateType?.map(ct => {
- if (ct === GetCertificateIdUseEnumType.V2GCertificateChain) {
- return InstallCertificateUseEnumType.V2GRootCertificate
- }
- return ct as unknown as InstallCertificateUseEnumType
- })
+ const filterTypes = certificateType?.map(ct => getCertificateIdUseToInstallCertificateUse[ct])
const methodResult = chargingStation.certificateManager.getInstalledCertificates(
chargingStation.stationInfo?.hashId ?? '',
connectorId,
connectorStatus: ConnectorStatusEnum.Available,
evseId,
- } as unknown as OCPP20StatusNotificationRequest)
+ })
chargingStation.unlockConnector(connectorId)
return { status: UnlockStatusEnumType.Unlocked }
for (const [connectorId, connector] of evseStatus.connectors) {
if (
connector.status != null &&
+ isOCPP20ConnectorStatus(connector.status) &&
!stationState.preInoperativeConnectorStatuses.has(connectorId)
) {
- stationState.preInoperativeConnectorStatuses.set(
- connectorId,
- connector.status as unknown as OCPP20ConnectorStatusEnumType
- )
+ stationState.preInoperativeConnectorStatuses.set(connectorId, connector.status)
}
}
}
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: status,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.sendAllConnectorsStatusNotifications: Error sending status notification for connector ${connectorId.toString()}:`,
error
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: status,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.sendEvseStatusNotifications: Error sending status notification for connector ${connectorId.toString()}:`,
error
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: restoredStatus,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.sendRestoredAllConnectorsStatusNotifications: Error sending status notification for connector ${connectorId.toString()}:`,
error
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: restoredStatus,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.sendRestoredEvseStatusNotifications: Error sending status notification for connector ${connectorId.toString()}:`,
error
)) {
const resolvedStatus = connectorStatus.status ?? ConnectorStatusEnum.Available
chargingStation.ocppRequestService
- .requestHandler<OCPP20StatusNotificationRequest, OCPP20StatusNotificationResponse>(
+ .requestHandler<StatusNotificationOptions, OCPP20StatusNotificationResponse>(
chargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
{
connectorId,
connectorStatus: resolvedStatus,
evseId,
- } as unknown as OCPP20StatusNotificationRequest,
+ },
{ skipBufferingOnError: true, triggerMessage: true }
)
.catch(errorHandler)
const connectorStatus = evseStatus?.connectors.get(evse.connectorId)
const resolvedStatus = connectorStatus?.status ?? ConnectorStatusEnum.Available
chargingStation.ocppRequestService
- .requestHandler<OCPP20StatusNotificationRequest, OCPP20StatusNotificationResponse>(
+ .requestHandler<StatusNotificationOptions, OCPP20StatusNotificationResponse>(
chargingStation,
OCPP20RequestCommand.STATUS_NOTIFICATION,
{
connectorId: evse.connectorId,
connectorStatus: resolvedStatus,
evseId: evse.id,
- } as unknown as OCPP20StatusNotificationRequest,
+ },
{ skipBufferingOnError: true, triggerMessage: true }
)
.catch(errorHandler)
OCPP20RequestCommand,
OCPP20RequiredVariableName,
type OCPP20SignCertificateRequest,
- type OCPP20StatusNotificationRequest,
type OCPP20TransactionEventOptions,
OCPPVersion,
type RequestParams,
+ type StatusNotificationOptions,
} from '../../../types/index.js'
import { generateUUID, getErrorMessage, logger } from '../../../utils/index.js'
import { OCPPRequestService } from '../OCPPRequestService.js'
const moduleName = 'OCPP20RequestService'
+interface SignCertificateOptions extends JsonObject {
+ certificateType?: CertificateSigningUseEnumType
+}
+
/**
* OCPP 2.0.1 Request Service
*
const requestPayload =
params?.rawPayload === true
? (commandParams as RequestType)
- : this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams)
+ : this.buildRequestPayload(chargingStation, commandName, commandParams)
const messageId = generateUUID()
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
throw new OCPPError(ErrorType.NOT_SUPPORTED, errorMsg, commandName, commandParams)
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- private buildRequestPayload<Request extends JsonType>(
+ private buildRequestPayload (
chargingStation: ChargingStation,
commandName: OCPP20RequestCommand,
commandParams?: JsonType
- ): Request {
+ ): JsonType {
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.buildRequestPayload: Building '${commandName}' payload`
)
case OCPP20RequestCommand.NOTIFY_CUSTOMER_INFORMATION:
case OCPP20RequestCommand.NOTIFY_REPORT:
case OCPP20RequestCommand.SECURITY_EVENT_NOTIFICATION:
- return commandParams as unknown as Request
+ return commandParams ?? OCPP20Constants.OCPP_REQUEST_EMPTY
case OCPP20RequestCommand.HEARTBEAT:
- return OCPP20Constants.OCPP_RESPONSE_EMPTY as unknown as Request
+ return OCPP20Constants.OCPP_REQUEST_EMPTY
case OCPP20RequestCommand.SIGN_CERTIFICATE: {
let csr: string
try {
)
}
- const certificateType = (commandParams as JsonObject | undefined)?.certificateType as
- CertificateSigningUseEnumType | undefined
+ const certificateType = (commandParams as SignCertificateOptions | undefined)
+ ?.certificateType
const requestPayload: OCPP20SignCertificateRequest = {
csr,
...(certificateType != null && { certificateType }),
}
- return requestPayload as unknown as Request
+ return requestPayload
}
case OCPP20RequestCommand.STATUS_NOTIFICATION:
return OCPP20ServiceUtils.buildStatusNotificationRequest(
chargingStation,
- commandParams as unknown as OCPP20StatusNotificationRequest
- ) as unknown as Request
+ commandParams as StatusNotificationOptions
+ )
case OCPP20RequestCommand.TRANSACTION_EVENT:
return buildTransactionEvent(
chargingStation,
- commandParams as unknown as OCPP20TransactionEventOptions
- ) as unknown as Request
+ commandParams as OCPP20TransactionEventOptions
+ )
default: {
// OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
const errorMsg = `Unsupported OCPP command ${commandName as string} for payload building`
type OCPP20SecurityEventNotificationResponse,
type OCPP20SignCertificateRequest,
type OCPP20SignCertificateResponse,
- type OCPP20StatusNotificationRequest,
type OCPP20StatusNotificationResponse,
OCPP20TransactionEventEnumType,
type OCPP20TransactionEventRequest,
sendAndSetConnectorStatus(chargingStation, {
connectorId,
connectorStatus: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP20StatusNotificationRequest).catch((error: unknown) => {
+ }).catch((error: unknown) => {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.handleResponseTransactionEvent: Error sending StatusNotification(Occupied):`,
error
OCPP20AuthorizationStatusEnumType,
OCPP20ChargingStateEnumType,
OCPP20ComponentName,
- type OCPP20ConnectorStatusEnumType,
+ OCPP20ConnectorStatusEnumType,
type OCPP20EVSEType,
type OCPP20GetVariableResultType,
OCPP20IdTokenEnumType,
ReasonCodeEnumType,
RequestCommand,
type StartTransactionResult,
+ type StatusNotificationOptions,
type StopTransactionReason,
type StopTransactionResult,
type UUIDv4,
const moduleName = 'OCPP20ServiceUtils'
+export const isOCPP20ConnectorStatus = (
+ status: ConnectorStatusEnum
+): status is OCPP20ConnectorStatusEnumType =>
+ Object.values(OCPP20ConnectorStatusEnumType).some(value => value === status)
+
export interface RejectionReason {
additionalInfo: string
reasonCode: ReasonCodeEnumType
/**
* @param chargingStation - Target charging station for EVSE resolution
- * @param commandParams - Status notification parameters
+ * @param commandParams - StatusNotification input; `connectorStatus` takes precedence over `status`
* @returns Formatted OCPP 2.0.1 StatusNotification request payload
+ * @throws {OCPPError} When the EVSE id cannot be resolved or the connector status is missing/not a valid OCPP 2.0.1 status
*/
public static buildStatusNotificationRequest (
chargingStation: ChargingStation,
- commandParams: OCPP20StatusNotificationRequest
+ commandParams: StatusNotificationOptions
): OCPP20StatusNotificationRequest {
- const params = commandParams as Record<string, unknown>
- const connectorId = params.connectorId as number
- const connectorStatus = (params.connectorStatus ?? params.status) as ConnectorStatusEnum
- const evseId = params.evseId as number | undefined
+ const { connectorId, evseId } = commandParams
+ const connectorStatus = commandParams.connectorStatus ?? commandParams.status
const resolvedEvseId = evseId ?? chargingStation.getEvseIdByConnectorId(connectorId)
if (resolvedEvseId === undefined) {
throw new OCPPError(
RequestCommand.STATUS_NOTIFICATION
)
}
+ if (connectorStatus == null || !isOCPP20ConnectorStatus(connectorStatus)) {
+ throw new OCPPError(
+ ErrorType.INTERNAL_ERROR,
+ `Cannot build status notification payload: invalid connector status for connector ${connectorId.toString()}`,
+ RequestCommand.STATUS_NOTIFICATION
+ )
+ }
return {
connectorId,
- connectorStatus: connectorStatus as OCPP20ConnectorStatusEnumType,
+ connectorStatus,
evseId: resolvedEvseId,
timestamp: new Date(),
} satisfies OCPP20StatusNotificationRequest
)
const response = await chargingStation.ocppRequestService.requestHandler<
- OCPP20TransactionEventRequest,
+ OCPP20TransactionEventOptions,
OCPP20TransactionEventResponse
>(chargingStation, OCPP20RequestCommand.TRANSACTION_EVENT, {
connectorId,
transactionId,
triggerReason,
...options,
- } as unknown as OCPP20TransactionEventRequest)
+ })
return response
} catch (error) {
type ConnectorStatus,
ConnectorStatusEnum,
ErrorType,
- type OCPP16ChargePointErrorCode,
OCPPVersion,
RequestCommand,
- type StatusNotificationRequest,
+ type StatusNotificationOptions,
type StatusNotificationResponse,
} from '../../types/index.js'
import { logger } from '../../utils/index.js'
/**
* Sends a StatusNotification request and updates the connector status locally.
* @param chargingStation - Target charging station
- * @param commandParams - Status notification parameters including connector ID and status
+ * @param commandParams - Cross-version StatusNotification input; `connectorStatus` (OCPP 2.0.1) takes precedence over `status` (OCPP 1.6)
* @param options - Optional settings to control whether the request is actually sent
* @param options.send - Whether to actually send the status notification
*/
export const sendAndSetConnectorStatus = async (
chargingStation: ChargingStation,
- commandParams: StatusNotificationRequest,
+ commandParams: StatusNotificationOptions,
options?: { send: boolean }
): Promise<void> => {
options = { send: true, ...options }
- const params = commandParams as Record<string, unknown>
- const connectorId = params.connectorId as number
- const status = (params.connectorStatus ?? params.status) as ConnectorStatusEnum
- const errorCode = params.errorCode as OCPP16ChargePointErrorCode | undefined
+ const { connectorId, errorCode } = commandParams
+ const status = commandParams.connectorStatus ?? commandParams.status
const connectorStatus = chargingStation.getConnectorStatus(connectorId)
if (connectorStatus == null) {
return
if (options.send) {
checkConnectorStatusTransition(chargingStation, connectorId, status)
await chargingStation.ocppRequestService.requestHandler<
- StatusNotificationRequest,
+ StatusNotificationOptions,
StatusNotificationResponse
>(chargingStation, RequestCommand.STATUS_NOTIFICATION, commandParams)
}
connectorId,
connectorStatus: status,
status,
- } as unknown as StatusNotificationRequest)
+ })
}
/**
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: ConnectorStatusEnum.Reserved,
- } as unknown as StatusNotificationRequest)
+ })
} else if (connectorStatus?.status !== ConnectorStatusEnum.Available) {
await sendAndSetConnectorStatus(chargingStation, {
connectorId,
status: ConnectorStatusEnum.Available,
- } as unknown as StatusNotificationRequest)
+ })
}
}
const checkConnectorStatusTransition = (
chargingStation: ChargingStation,
connectorId: number,
- status: ConnectorStatusEnum
+ status: ConnectorStatusEnum | undefined
): boolean => {
const fromStatus = chargingStation.getConnectorStatus(connectorId)?.status
let chargingStationTransitions: readonly { from?: ConnectorStatusEnum; to: ConnectorStatusEnum }[]
} connector id ${connectorId.toString()} status transition from '${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
chargingStation.getConnectorStatus(connectorId)?.status
- }' to '${status}' is not allowed`
+ }' to '${
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+ status
+ }' is not allowed`
)
}
return transitionAllowed
*/
protected abstract resetStationState (stationState: TStationState): void
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- bridges contravariant handler signatures into IncomingRequestHandler
- protected toRequestHandler<P extends JsonType, R extends JsonType>(
- handler: (chargingStation: ChargingStation, commandPayload: P) => Promise<R> | R
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- P bridges contravariant handler payload signatures into IncomingRequestHandler
+ protected toRequestHandler<P extends JsonType>(
+ handler: (chargingStation: ChargingStation, commandPayload: P) => JsonType | Promise<JsonType>
): IncomingRequestHandler {
- return handler as unknown as IncomingRequestHandler
+ return handler as IncomingRequestHandler
}
/**
requestPayload: R
) => Promise<void> | void
): ResponseHandler {
- return handler as unknown as ResponseHandler
+ return handler as ResponseHandler
}
/**
* @returns True if OCPP 2.0.1 type
*/
export const isOCPP20Type = (type: IdentifierType): boolean => {
- return Object.values(OCPP20IdTokenEnumType).includes(type as unknown as OCPP20IdTokenEnumType)
+ return (Object.values(OCPP20IdTokenEnumType) as string[]).includes(type)
}
/**
type RequestParams,
type ResponseCallback,
type ResponseType,
+ type StatusNotificationOptions,
type StatusNotificationRequest,
} from './ocpp/Requests.js'
export {
* Optional parameters for building and sending TransactionEvent requests.
* Aligned with OCPP 2.0.1 TransactionEvent.req optional fields.
*/
-export interface OCPP20TransactionEventOptions {
+export interface OCPP20TransactionEventOptions extends JsonObject {
cableMaxCurrent?: number
chargingState?: OCPP20ChargingStateEnumType
connectorId?: number
import type { ChargingStation } from '../../charging-station/index.js'
import type { OCPPError } from '../../exception/index.js'
-import type { JsonType } from '../JsonType.js'
+import type { JsonObject, JsonType } from '../JsonType.js'
+import type { OCPP16ChargePointErrorCode } from './1.6/ChargePointErrorCode.js'
import type { OCPP16MeterValuesRequest } from './1.6/MeterValues.js'
import type { OCPP20MeterValuesRequest } from './2.0/MeterValues.js'
+import type { ConnectorStatusEnum } from './ConnectorStatusEnum.js'
import type { MessageType } from './MessageType.js'
import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus.js'
export type ResponseCallback = (payload: JsonType, requestPayload: JsonType) => void
+/**
+ * Cross-version (OCPP 1.6/2.0.1) input for a StatusNotification request, looser than the per-version
+ * wire types it is built into. `connectorStatus` (2.0.1) takes precedence over `status` (1.6).
+ */
+export interface StatusNotificationOptions extends JsonObject {
+ connectorId: number
+ connectorStatus?: ConnectorStatusEnum
+ errorCode?: OCPP16ChargePointErrorCode
+ evseId?: number
+ info?: string
+ status?: ConnectorStatusEnum
+ timestamp?: Date
+ vendorErrorCode?: string
+ vendorId?: string
+}
+
export type StatusNotificationRequest =
OCPP16StatusNotificationRequest | OCPP20StatusNotificationRequest
import { OCPP20ServiceUtils } from '../../../../src/charging-station/ocpp/2.0/OCPP20ServiceUtils.js'
import { OCPPError } from '../../../../src/exception/index.js'
import {
+ OCPP16ChargePointStatus,
OCPP20ConnectorStatusEnumType,
type OCPP20StatusNotificationRequest,
OCPPVersion,
+ type StatusNotificationOptions,
} from '../../../../src/types/index.js'
import { Constants } from '../../../../src/utils/index.js'
import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js'
assert.strictEqual(result.connectorStatus, OCPP20ConnectorStatusEnumType.Faulted)
})
+
+ await it('should throw OCPPError when connectorStatus and status are both missing', () => {
+ const input: StatusNotificationOptions = {
+ connectorId: 1,
+ evseId: 1,
+ }
+
+ assert.throws(
+ () => {
+ OCPP20ServiceUtils.buildStatusNotificationRequest(mockStation, input)
+ },
+ (error: unknown) => {
+ assert.ok(error instanceof OCPPError)
+ return true
+ }
+ )
+ })
+
+ await it('should throw OCPPError when connectorStatus is not a valid OCPP 2.0.1 status', () => {
+ const input: StatusNotificationOptions = {
+ connectorId: 1,
+ connectorStatus: OCPP16ChargePointStatus.Preparing,
+ evseId: 1,
+ }
+
+ assert.throws(
+ () => {
+ OCPP20ServiceUtils.buildStatusNotificationRequest(mockStation, input)
+ },
+ (error: unknown) => {
+ assert.ok(error instanceof OCPPError)
+ return true
+ }
+ )
+ })
})
})
restoreConnectorStatus,
sendAndSetConnectorStatus,
} from '../../../src/charging-station/ocpp/OCPPConnectorStatusOperations.js'
-import {
- ConnectorStatusEnum,
- type OCPP16StatusNotificationRequest,
- type OCPP20StatusNotificationRequest,
- OCPPVersion,
-} from '../../../src/types/index.js'
+import { ConnectorStatusEnum, OCPPVersion } from '../../../src/types/index.js'
import {
createStationWithRequestHandler,
standardCleanup,
await sendAndSetConnectorStatus(station, {
connectorId: 1,
status: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP16StatusNotificationRequest)
+ })
assert.strictEqual(requestHandler.mock.calls.length, 1)
assert.strictEqual(station.getConnectorStatus(1)?.status, ConnectorStatusEnum.Occupied)
await sendAndSetConnectorStatus(station, {
connectorId: 99,
status: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP16StatusNotificationRequest)
+ })
assert.strictEqual(requestHandler.mock.calls.length, 0)
})
{
connectorId: 1,
status: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP16StatusNotificationRequest,
+ },
{
send: false,
}
await sendAndSetConnectorStatus(station, {
connectorId: 1,
status: ConnectorStatusEnum.Unavailable,
- } as unknown as OCPP16StatusNotificationRequest)
+ })
assert.strictEqual(station.getConnectorStatus(1)?.status, ConnectorStatusEnum.Unavailable)
})
await sendAndSetConnectorStatus(station, {
connectorId: 1,
status: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP16StatusNotificationRequest)
+ })
assert.strictEqual(emitSpy.mock.calls.length, 1)
})
connectorId: 1,
connectorStatus: ConnectorStatusEnum.Occupied,
evseId: 1,
- } as unknown as OCPP20StatusNotificationRequest)
+ })
assert.strictEqual(requestHandler.mock.calls.length, 1)
assert.strictEqual(station.getConnectorStatus(1)?.status, ConnectorStatusEnum.Occupied)
await sendAndSetConnectorStatus(station, {
connectorId: 1,
status: ConnectorStatusEnum.Occupied,
- } as unknown as OCPP16StatusNotificationRequest)
+ })
assert.strictEqual(requestHandler.mock.calls.length, 1)
})