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 { 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 {} }