logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Building request payload for '${commandName}'`
)
- const requestPayload = this.buildRequestPayload<RequestType>(
- chargingStation,
- commandName,
- commandParams
- )
+ const requestPayload =
+ params?.rawPayload === true
+ ? (commandParams as RequestType)
+ : this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams)
const messageId = generateUUID()
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
...commandParams,
} as unknown as Request
case OCPP16RequestCommand.STATUS_NOTIFICATION:
- if (commandParams.errorCode != null) {
- return commandParams as unknown as Request
- }
return buildStatusNotificationRequest(
chargingStation,
commandParams.connectorId as number,
import type { ValidateFunction } from 'ajv'
import type { ChargingStation } from '../../../charging-station/index.js'
-import type {
- ConnectorStatusEnum,
- OCPP20TransactionEventEnumType,
- OCPP20TriggerReasonEnumType,
-} from '../../../types/index.js'
import type { OCPP20TransactionEventOptions } from '../../../types/ocpp/2.0/Transaction.js'
import type { OCPPResponseService } from '../OCPPResponseService.js'
import { OCPPError } from '../../../exception/index.js'
import {
type CertificateSigningUseEnumType,
+ type ConnectorStatusEnum,
ErrorType,
type JsonObject,
type JsonType,
OCPP20RequestCommand,
type OCPP20SignCertificateRequest,
+ OCPP20TransactionEventEnumType,
+ OCPP20TriggerReasonEnumType,
OCPPVersion,
type RequestParams,
} from '../../../types/index.js'
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Building request payload for '${commandName}'`
)
- const requestPayload = this.buildRequestPayload<RequestType>(
- chargingStation,
- commandName,
- commandParams
- )
+ const requestPayload =
+ params?.rawPayload === true
+ ? (commandParams as RequestType)
+ : this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams)
const messageId = generateUUID()
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.requestHandler: Sending '${commandName}' request with message ID '${messageId}'`
commandParams.evseId as number | undefined
) as unknown as Request
case OCPP20RequestCommand.TRANSACTION_EVENT: {
- // Pre-built payloads (e.g., from offline queue) already have transactionInfo;
- // pass them through as-is to avoid double-building.
- if (commandParams.transactionInfo != null) {
- return commandParams as unknown as Request
- }
const eventType = commandParams.eventType as OCPP20TransactionEventEnumType
- const triggerReason = commandParams.triggerReason as OCPP20TriggerReasonEnumType
- const connectorId = commandParams.connectorId as number
- const transactionId = commandParams.transactionId as string
+ const triggerReason: OCPP20TriggerReasonEnumType =
+ commandParams.triggerReason != null
+ ? (commandParams.triggerReason as OCPP20TriggerReasonEnumType)
+ : eventType === OCPP20TransactionEventEnumType.Ended
+ ? OCPP20TriggerReasonEnumType.RemoteStop
+ : OCPP20TriggerReasonEnumType.Authorized
+ const evse = commandParams.evse as undefined | { connectorId?: number; id?: number }
+ const connectorId: number =
+ commandParams.connectorId != null
+ ? (commandParams.connectorId as number)
+ : (evse?.connectorId ?? evse?.id ?? 1)
+ const transactionId: string =
+ commandParams.transactionId != null
+ ? (commandParams.transactionId as string)
+ : eventType === OCPP20TransactionEventEnumType.Ended
+ ? (chargingStation.getConnectorStatus(connectorId)?.transactionId?.toString() ??
+ generateUUID())
+ : generateUUID()
return OCPP20ServiceUtils.buildTransactionEvent(
chargingStation,
eventType,
await chargingStation.ocppRequestService.requestHandler<
OCPP20TransactionEventRequest,
OCPP20TransactionEventResponse
- >(chargingStation, OCPP20RequestCommand.TRANSACTION_EVENT, queuedEvent.request)
+ >(chargingStation, OCPP20RequestCommand.TRANSACTION_EVENT, queuedEvent.request, {
+ rawPayload: true,
+ })
} catch (error) {
logger.error(
`${chargingStation.logPrefix()} ${moduleName}.sendQueuedTransactionEvents: Failed to send queued TransactionEvent with seqNo=${queuedEvent.seqNo.toString()}:`,
throw new OCPPError(ErrorType.PROPERTY_CONSTRAINT_VIOLATION, errorMsg)
}
- // Offline path: build payload directly for queueing (queue stores pre-built requests
- // that are sent as-is on reconnect, bypassing buildRequestPayload).
+ // Offline: build and queue pre-built payload (sent as-is via rawPayload on reconnect)
if (!chargingStation.isWebSocketConnectionOpened()) {
const transactionEventRequest = OCPP20ServiceUtils.buildTransactionEvent(
chargingStation,
return { idTokenInfo: undefined }
}
- // Online path: pass minimal params to requestHandler → buildRequestPayload builds
+ // Online: minimal params → requestHandler → buildRequestPayload
logger.debug(
`${chargingStation.logPrefix()} ${moduleName}.sendTransactionEvent: Sending TransactionEvent for trigger ${triggerReason}`
)
export type RequestCommand = OCPP16RequestCommand | OCPP20RequestCommand
export interface RequestParams {
+ rawPayload?: boolean
skipBufferingOnError?: boolean
throwError?: boolean
triggerMessage?: boolean
const args = requestHandlerMock.mock.calls[0].arguments as [
unknown,
string,
- Record<string, unknown>
+ Partial<OCPP20TransactionEventRequest>
]
const minimalParams = args[2]
import { afterEach, beforeEach, describe, it, mock } from 'node:test'
import type {
+ OCPP20StatusNotificationRequest,
OCPP20TriggerMessageRequest,
OCPP20TriggerMessageResponse,
+ RequestParams,
} from '../../../../src/types/index.js'
import type { MockChargingStation } from '../../ChargingStationTestUtils.js'
const args = call.arguments as [
unknown,
string,
- Record<string, unknown>,
- Record<string, unknown>
+ Partial<OCPP20StatusNotificationRequest>,
+ RequestParams
]
const [, command, payload, options] = args
assert.strictEqual(command, OCPP20RequestCommand.STATUS_NOTIFICATION)
assert.ok('evseId' in payload, 'Expected payload to include evseId')
assert.ok('connectorId' in payload, 'Expected payload to include connectorId')
assert.ok('status' in payload, 'Expected payload to include status')
- assert.ok((payload.evseId as number) > 0, 'Expected evseId > 0 (EVSE 0 excluded)')
+ assert.ok(
+ payload.evseId != null && payload.evseId > 0,
+ 'Expected evseId > 0 (EVSE 0 excluded)'
+ )
assert.strictEqual(options.skipBufferingOnError, true)
assert.strictEqual(options.triggerMessage, true)
}
const args = requestHandlerMock.mock.calls[0].arguments as [
unknown,
string,
- Record<string, unknown>,
- Record<string, unknown>
+ Partial<OCPP20StatusNotificationRequest>,
+ RequestParams
]
const [, command, payload, options] = args
assert.strictEqual(command, OCPP20RequestCommand.STATUS_NOTIFICATION)
type OCPP20IdTokenType,
OCPP20ReasonEnumType,
type OCPP20TransactionContext,
+ type OCPP20TransactionType,
} from '../../../../src/types/ocpp/2.0/Transaction.js'
import { Constants, generateUUID } from '../../../../src/utils/index.js'
import { standardCleanup } from '../../../helpers/TestLifecycleHelpers.js'
assert.strictEqual(sentRequests.length, 1)
assert.strictEqual(
- (sentRequests[0].payload.transactionInfo as Record<string, unknown>).transactionId,
+ (sentRequests[0].payload.transactionInfo as OCPP20TransactionType).transactionId,
transactionId1
)
assert.strictEqual(sentRequests.length, 2)
assert.strictEqual(
- (sentRequests[1].payload.transactionInfo as Record<string, unknown>).transactionId,
+ (sentRequests[1].payload.transactionInfo as OCPP20TransactionType).transactionId,
transactionId2
)
})