import { useDrizzle } from '@/lib/db.js' import dayjs from 'dayjs' import { chargePoint } from '@/db/schema.js' import { getOcpp16jSettings } from '@/lib/system-settings.js' import type { BootNotificationRequest, BootNotificationResponse, OcppConnectionContext, } from '../types.ts' export async function handleBootNotification( payload: BootNotificationRequest, ctx: OcppConnectionContext, ): Promise { console.info( `[OCPP][ACTION][BootNotification][BEGIN] cp=${ctx.chargePointIdentifier} vendor=${payload.chargePointVendor} model=${payload.chargePointModel} fw=${payload.firmwareVersion ?? 'n/a'}`, ) const db = useDrizzle() const { heartbeatInterval } = await getOcpp16jSettings() 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, lastBootNotificationAt: dayjs().toDate(), transportStatus: 'online', }) .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, lastBootNotificationAt: dayjs().toDate(), transportStatus: 'online', updatedAt: dayjs().toDate(), }, }) .returning() const status = cp.registrationStatus ctx.isRegistered = status === 'Accepted' console.info( `[OCPP][ACTION][BootNotification][END] cp=${ctx.chargePointIdentifier} status=${status} heartbeatInterval=${heartbeatInterval}`, ) return { currentTime: dayjs().toISOString(), interval: heartbeatInterval, status, } }