From 8f3b2fd6e2f15824f1c2489530fa69c45cfa5e35 Mon Sep 17 00:00:00 2001 From: Timothy Yin Date: Sun, 15 Mar 2026 04:28:32 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"feat(boot-notification):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=B6=85=E6=97=B6=E5=A4=84=E7=90=86=E5=92=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E4=BB=A5=E5=A2=9E=E5=BC=BA=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E9=80=9A=E7=9F=A5=E7=9A=84=E6=8C=81=E4=B9=85=E6=80=A7?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8a537e80e3b07c112a1d7436f367622ebedf474a. --- apps/csms/src/lib/db.ts | 2 - .../src/ocpp/actions/boot-notification.ts | 114 +++++++----------- 2 files changed, 43 insertions(+), 73 deletions(-) diff --git a/apps/csms/src/lib/db.ts b/apps/csms/src/lib/db.ts index 9ae54a4..e0b5e7e 100644 --- a/apps/csms/src/lib/db.ts +++ b/apps/csms/src/lib/db.ts @@ -9,8 +9,6 @@ export const useDrizzle = () => { if (!pgPoolInstance || !drizzleInstance) { pgPoolInstance = new Pool({ connectionString: process.env.DATABASE_CONNECTION_STRING, - connectionTimeoutMillis: 3000, - idleTimeoutMillis: 10000, }) drizzleInstance = drizzle({ client: pgPoolInstance, schema }) } diff --git a/apps/csms/src/ocpp/actions/boot-notification.ts b/apps/csms/src/ocpp/actions/boot-notification.ts index d5a2150..c3a9985 100644 --- a/apps/csms/src/ocpp/actions/boot-notification.ts +++ b/apps/csms/src/ocpp/actions/boot-notification.ts @@ -8,86 +8,58 @@ import type { } from '../types.ts' const DEFAULT_HEARTBEAT_INTERVAL = 60 -const BOOT_NOTIFICATION_DB_TIMEOUT_MS = 3000 - -function withTimeout(promise: Promise, timeoutMs: number, label: string) { - return Promise.race([ - promise, - new Promise((_, reject) => { - setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs) - }), - ]) -} export async function handleBootNotification( payload: BootNotificationRequest, ctx: OcppConnectionContext, ): Promise { const db = useDrizzle() - const currentTime = dayjs().toISOString() - console.log(`[OCPP] BootNotification ${ctx.chargePointIdentifier} received`) + 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() - try { - const [cp] = await withTimeout( - 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(), - BOOT_NOTIFICATION_DB_TIMEOUT_MS, - `BootNotification persistence for ${ctx.chargePointIdentifier}`, - ) + const status = cp.registrationStatus + ctx.isRegistered = status === 'Accepted' - const status = cp.registrationStatus - ctx.isRegistered = status === 'Accepted' + console.log(`[OCPP] BootNotification ${ctx.chargePointIdentifier} status=${status}`) - console.log(`[OCPP] BootNotification ${ctx.chargePointIdentifier} status=${status}`) - - return { - currentTime, - interval: DEFAULT_HEARTBEAT_INTERVAL, - status, - } - } catch (error) { - ctx.isRegistered = false - console.error(`[OCPP] BootNotification ${ctx.chargePointIdentifier} persistence failed:`, error) - - return { - currentTime, - interval: DEFAULT_HEARTBEAT_INTERVAL, - status: 'Pending', - } + return { + currentTime: dayjs().toISOString(), + interval: DEFAULT_HEARTBEAT_INTERVAL, + status, } }