Files
helios-evcs/apps/csms/src/ocpp/actions/status-notification.ts

105 lines
2.9 KiB
TypeScript

import { eq, and } from 'drizzle-orm'
import { useDrizzle } from '@/lib/db.js'
import { chargePoint, connector, connectorStatusHistory } from '@/db/schema.js'
import type {
StatusNotificationRequest,
StatusNotificationResponse,
OcppConnectionContext,
} from '../types.ts'
// Mirror the enum values defined in ocpp-schema.ts for type safety
type ConnectorStatus =
| 'Available'
| 'Preparing'
| 'Charging'
| 'SuspendedEVSE'
| 'SuspendedEV'
| 'Finishing'
| 'Reserved'
| 'Unavailable'
| 'Faulted'
type ConnectorErrorCode =
| 'NoError'
| 'ConnectorLockFailure'
| 'EVCommunicationError'
| 'GroundFailure'
| 'HighTemperature'
| 'InternalError'
| 'LocalListConflict'
| 'OtherError'
| 'OverCurrentFailure'
| 'OverVoltage'
| 'PowerMeterFailure'
| 'PowerSwitchFailure'
| 'ReaderFailure'
| 'ResetFailure'
| 'UnderVoltage'
| 'WeakSignal'
export async function handleStatusNotification(
payload: StatusNotificationRequest,
ctx: OcppConnectionContext,
): Promise<StatusNotificationResponse> {
const db = useDrizzle()
// Retrieve the internal charge point id
const [cp] = await db
.select({ id: chargePoint.id })
.from(chargePoint)
.where(eq(chargePoint.chargePointIdentifier, ctx.chargePointIdentifier))
.limit(1)
if (!cp) {
throw new Error(`ChargePoint not found: ${ctx.chargePointIdentifier}`)
}
const statusTimestamp = payload.timestamp ? new Date(payload.timestamp) : new Date()
const connStatus = payload.status as ConnectorStatus
const connErrorCode = payload.errorCode as ConnectorErrorCode
// Upsert connector and return the internal id for history insertion
const [upsertedConnector] = await db
.insert(connector)
.values({
id: crypto.randomUUID(),
chargePointId: cp.id,
connectorId: payload.connectorId,
status: connStatus,
errorCode: connErrorCode,
info: payload.info ?? null,
vendorId: payload.vendorId ?? null,
vendorErrorCode: payload.vendorErrorCode ?? null,
lastStatusAt: statusTimestamp,
})
.onConflictDoUpdate({
target: [connector.chargePointId, connector.connectorId],
set: {
status: connStatus,
errorCode: connErrorCode,
info: payload.info ?? null,
vendorId: payload.vendorId ?? null,
vendorErrorCode: payload.vendorErrorCode ?? null,
lastStatusAt: statusTimestamp,
updatedAt: new Date(),
},
})
.returning({ id: connector.id })
if (upsertedConnector) {
await db.insert(connectorStatusHistory).values({
id: crypto.randomUUID(),
connectorId: upsertedConnector.id,
connectorNumber: payload.connectorId,
status: connStatus,
errorCode: connErrorCode,
info: payload.info ?? null,
vendorId: payload.vendorId ?? null,
vendorErrorCode: payload.vendorErrorCode ?? null,
statusTimestamp,
})
}
return {}
}