diff --git a/apps/csms/src/ocpp/handler.ts b/apps/csms/src/ocpp/handler.ts index b1f82e9..012c896 100644 --- a/apps/csms/src/ocpp/handler.ts +++ b/apps/csms/src/ocpp/handler.ts @@ -130,6 +130,17 @@ async function updateTransportState( .where(eq(chargePoint.chargePointIdentifier, chargePointIdentifier)) } +async function getRegistrationStatus(chargePointIdentifier: string) { + const db = useDrizzle() + const [cp] = await db + .select({ registrationStatus: chargePoint.registrationStatus }) + .from(chargePoint) + .where(eq(chargePoint.chargePointIdentifier, chargePointIdentifier)) + .limit(1) + + return cp?.registrationStatus ?? null +} + function getCommandChannelStatus(chargePointIdentifier: string): CommandChannelStatus { return ocppConnections.has(chargePointIdentifier) ? 'online' : 'unavailable' } @@ -211,6 +222,19 @@ export function createOcppHandler(chargePointIdentifier: string, remoteAddr?: st ws.close(1002, 'Unsupported subprotocol') return } + + const registrationStatus = await getRegistrationStatus(chargePointIdentifier) + ctx.isRegistered = registrationStatus === 'Accepted' + + const previous = ocppConnections.get(chargePointIdentifier) + if (previous && previous.sessionId !== sessionId) { + try { + previous.ws.close(1012, 'Replaced by newer connection') + } catch { + // Ignore close race when the old socket is already gone. + } + } + ocppConnections.set(chargePointIdentifier, { ws, sessionId, @@ -226,15 +250,24 @@ export function createOcppHandler(chargePointIdentifier: string, remoteAddr?: st `[OCPP] ${chargePointIdentifier} connected` + (remoteAddr ? ` from ${remoteAddr}` : ''), ) + if (previous && previous.sessionId !== sessionId) { + console.log(`[OCPP] ${chargePointIdentifier} replaced previous connection`) + } }, async onMessage(evt: MessageEvent, ws: WSContext) { let uniqueId = '(unknown)' try { const current = ocppConnections.get(chargePointIdentifier) - if (current) { - current.lastMessageAt = new Date() + if (!current || current.sessionId !== sessionId) { + try { + ws.close(1008, 'Stale connection') + } catch { + // Ignore close errors on stale sockets. + } + return } + current.lastMessageAt = new Date() const raw = evt.data if (typeof raw !== 'string') return