diff --git a/display/middleware/src/modules/mqtt/broker-manager.ts b/display/middleware/src/modules/mqtt/broker-manager.ts index fc4d368..cd73aa8 100644 --- a/display/middleware/src/modules/mqtt/broker-manager.ts +++ b/display/middleware/src/modules/mqtt/broker-manager.ts @@ -162,33 +162,40 @@ export function connectBroker(id: number): Promise { resolve(client); }); - client.on('message', (topic: string, payloadBuf: Buffer) => { + // Throttle DB writes: cache payloads in memory, flush periodically + const payloadCache = new Map(); + const flushPayloads = (): void => { const db = getDb(); - const payload = payloadBuf.toString(); + for (const [t, p] of payloadCache.entries()) { + const topicRecord = db + .prepare('SELECT * FROM mqtt_topics WHERE broker_id = ? AND topic = ?') + .get(id, t) as MqttTopic | undefined; + if (!topicRecord) continue; - // Find the topic record - const topicRecord = db - .prepare( - 'SELECT * FROM mqtt_topics WHERE broker_id = ? AND topic = ?' - ) - .get(id, topic) as MqttTopic | undefined; + db.run('UPDATE mqtt_topics SET last_payload = ? WHERE id = ?', [p, topicRecord.id]); - if (!topicRecord) return; + const extracted = extractValue(p, topicRecord.json_path); + if (extracted === null) continue; - // Update last_payload - db.run( - 'UPDATE mqtt_topics SET last_payload = ? WHERE id = ?', - [payload, topicRecord.id] - ); - - // Extract value and update datapoint - const extracted = extractValue(payload, topicRecord.json_path); - if (extracted === null) return; - - const dp = getDatapointByTopicId(topicRecord.id); - if (dp) { - updateDatapointValue(dp.id, extracted); + const dp = getDatapointByTopicId(topicRecord.id); + if (dp) { + updateDatapointValue(dp.id, extracted); + } } + payloadCache.clear(); + }; + + // Flush every 2 seconds + const flushTimer = setInterval(flushPayloads, 2000); + + client.on('message', (topic: string, payloadBuf: Buffer) => { + payloadCache.set(topic, payloadBuf.toString()); + }); + + // Clean up flush timer on disconnect + client.on('close', () => { + clearInterval(flushTimer); + flushPayloads(); }); client.on('error', (err: Error) => { diff --git a/display/middleware/src/modules/mqtt/topic-discovery.ts b/display/middleware/src/modules/mqtt/topic-discovery.ts index b9c1d88..eaff9f2 100644 --- a/display/middleware/src/modules/mqtt/topic-discovery.ts +++ b/display/middleware/src/modules/mqtt/topic-discovery.ts @@ -87,24 +87,37 @@ export function startDiscovery(brokerId: number, prefix?: string): Promise = new Set(); const finalize = (): void => { + clearInterval(flushInterval); + flushToDb(); // Final flush if (tempClient) { tempClient.end(true); } resolve(getTopicsForBroker(brokerId)); }; - const onMessage = (topic: string, payload: Buffer): void => { - const payloadStr = payload.toString(); - if (!discoveredTopics.has(topic)) { - discoveredTopics.add(topic); - ensureTopicExists(brokerId, topic); - } - // Always update last_payload so the user sees the latest value + // Collect payloads in memory, batch-write to DB periodically + const payloadCache: Map = new Map(); + + const flushToDb = (): void => { const db = getDb(); - db.run( - 'UPDATE mqtt_topics SET last_payload = ? WHERE broker_id = ? AND topic = ?', - [payloadStr, brokerId, topic] - ); + for (const [t, p] of payloadCache.entries()) { + if (!discoveredTopics.has(t)) { + discoveredTopics.add(t); + ensureTopicExists(brokerId, t); + } + db.run( + 'UPDATE mqtt_topics SET last_payload = ? WHERE broker_id = ? AND topic = ?', + [p, brokerId, t] + ); + } + payloadCache.clear(); + }; + + // Flush every 2 seconds instead of on every message + const flushInterval = setInterval(flushToDb, 2000); + + const onMessage = (topic: string, payload: Buffer): void => { + payloadCache.set(topic, payload.toString()); }; if (existingClient && existingClient.connected) {