import { useDrizzle } from '@/lib/db.js' import dayjs from 'dayjs' import { chargePoint } from '@/db/schema.js' import type { BootNotificationRequest, BootNotificationResponse, OcppConnectionContext, } from '../types.ts' const DEFAULT_HEARTBEAT_INTERVAL = 60 export async function handleBootNotification( payload: BootNotificationRequest, ctx: OcppConnectionContext, ): Promise { const db = useDrizzle() const [cp] = await db .insert(chargePoint) .values({ id: crypto.randomUUID(), chargePointIdentifier: ctx.chargePointIdentifier, chargePointVendor: payload.chargePointVendor, chargePointModel: payload.chargePointModel, chargePointSerialNumber: payload.chargePointSerialNumber ?? null, firmwareVersion: payload.firmwareVersion ?? null, iccid: payload.iccid ?? null, imsi: payload.imsi ?? null, meterType: payload.meterType ?? null, meterSerialNumber: payload.meterSerialNumber ?? null, // New, unknown devices start as Pending — admin must manually accept them registrationStatus: 'Pending', heartbeatInterval: DEFAULT_HEARTBEAT_INTERVAL, lastBootNotificationAt: dayjs().toDate(), }) .onConflictDoUpdate({ target: chargePoint.chargePointIdentifier, set: { chargePointVendor: payload.chargePointVendor, chargePointModel: payload.chargePointModel, chargePointSerialNumber: payload.chargePointSerialNumber ?? null, firmwareVersion: payload.firmwareVersion ?? null, iccid: payload.iccid ?? null, imsi: payload.imsi ?? null, meterType: payload.meterType ?? null, meterSerialNumber: payload.meterSerialNumber ?? null, // Do NOT override registrationStatus — preserve whatever the admin set heartbeatInterval: DEFAULT_HEARTBEAT_INTERVAL, lastBootNotificationAt: dayjs().toDate(), updatedAt: dayjs().toDate(), }, }) .returning() const status = cp.registrationStatus ctx.isRegistered = status === 'Accepted' console.log(`[OCPP] BootNotification ${ctx.chargePointIdentifier} status=${status}`) return { currentTime: dayjs().toISOString(), interval: DEFAULT_HEARTBEAT_INTERVAL, status, } }