diff --git a/src/lib/server/mqtt-devices.js b/src/lib/server/mqtt-devices.js new file mode 100644 index 0000000..8445506 --- /dev/null +++ b/src/lib/server/mqtt-devices.js @@ -0,0 +1,42 @@ +// src/lib/server/mqtt-devices.js +// This module provides access to MQTT device data for other parts of the application + +// We'll import the maps directly from the MQTT server module + +let connectedDevices = new Map(); +let deviceSensorData = new Map(); + +// Export the maps so the MQTT server can set them +export { connectedDevices, deviceSensorData }; + +// Clean up offline devices (not seen in last 5 minutes) +function cleanupDevices() { + const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); + let updated = false; + + for (const [deviceId, device] of connectedDevices.entries()) { + if (device.lastSeen < fiveMinutesAgo && device.status === "online") { + connectedDevices.set(deviceId, { ...device, status: "offline" }); + updated = true; + } + } + + return updated; +} + +// Export function to get current devices +export function getCurrentDevices() { + cleanupDevices(); + return Array.from(connectedDevices.values()).map((device) => { + const sensorData = deviceSensorData.get(device.id); + return { + ...device, + sensorData: sensorData || null, + }; + }); +} + +// Export function to get sensor data for a specific device +export function getDeviceSensorData(deviceId) { + return deviceSensorData.get(deviceId) || null; +} diff --git a/src/routes/(app)/[slug]/+page.server.ts b/src/routes/(app)/[slug]/+page.server.ts index 68d7496..8ce7412 100644 --- a/src/routes/(app)/[slug]/+page.server.ts +++ b/src/routes/(app)/[slug]/+page.server.ts @@ -3,6 +3,7 @@ import * as table from "$lib/server/db/schema"; import { eq } from "drizzle-orm"; import type { PageServerLoad } from "./$types"; import { connect } from "mqtt"; +import { getDeviceSensorData } from "$lib/server/mqtt-devices.js"; export const load: PageServerLoad = async ({ params }) => { // Convert slug to number for floor lookup @@ -18,6 +19,18 @@ export const load: PageServerLoad = async ({ params }) => { try { // Try to parse the saved configuration const config = JSON.parse(floorData[0].url); + + // Add real sensor data to devices + if (config.devices) { + config.devices = config.devices.map(device => { + const sensorData = getDeviceSensorData(device.id); + return { + ...device, + sensorData: sensorData + }; + }); + } + return { slug: params.slug, floorConfig: config, diff --git a/src/routes/(app)/[slug]/+page.svelte b/src/routes/(app)/[slug]/+page.svelte index 27ee060..3aa8411 100644 --- a/src/routes/(app)/[slug]/+page.svelte +++ b/src/routes/(app)/[slug]/+page.svelte @@ -6,22 +6,50 @@ let mqttMessage = $state("Waiting for MQTT message..."); let eventSource; + let deviceSensorData = $state(new Map()); + let refreshInterval; onMount(() => { // Connect to the SSE endpoint + console.log("Attempting to connect to MQTT SSE..."); eventSource = new EventSource("/mqtt"); eventSource.onopen = () => { - console.log("SSE connection opened."); + console.log("SSE connection opened successfully!"); }; eventSource.onmessage = (event) => { + if (eventSource.readyState !== EventSource.OPEN) { + console.log("Floor page: Received message but connection is not open, ignoring"); + return; + } + try { - const data = JSON.parse(event.data); - mqttMessage = data.message; - console.log("Received SSE message:", mqttMessage); + const messageData = JSON.parse(event.data); + console.log("Floor page received SSE data:", messageData); + + // Handle device updates + if (messageData.devices) { + console.log("Received devices:", messageData.devices); + const newData = new Map(); + messageData.devices.forEach((device) => { + console.log(`Device ${device.id} has sensor data:`, device.sensorData); + if (device.sensorData) { + newData.set(device.id, device.sensorData); + } + }); + deviceSensorData = newData; + console.log("Updated deviceSensorData:", deviceSensorData); + } + + // Handle MQTT message if present + if (messageData.message) { + mqttMessage = messageData.message; + } else { + mqttMessage = `Last update: ${messageData.timestamp}`; + } } catch (e) { - console.error("Error parsing SSE message:", e); + console.error("Floor page: Error parsing SSE message:", e, "Raw data:", event.data); } }; @@ -32,9 +60,12 @@ }); onDestroy(() => { - if (eventSource) { - console.log("Closing SSE connection."); - eventSource.close(); // Clean up the connection when the component is destroyed + if (eventSource && eventSource.readyState !== EventSource.CLOSED) { + console.log("Floor page: Closing SSE connection"); + eventSource.close(); + } + if (refreshInterval) { + clearInterval(refreshInterval); } }); @@ -114,19 +145,51 @@
- 23°C + + {#if deviceSensorData.get(device.id)?.temperature !== undefined} + {deviceSensorData.get(device.id).temperature.toFixed(1)}°C + {:else if device.sensorData} + {device.sensorData.temperature.toFixed(1)}°C + {:else} + --°C + {/if} +
- 45% + + {#if deviceSensorData.get(device.id)?.humidity !== undefined} + {deviceSensorData.get(device.id).humidity.toFixed(1)}% + {:else if device.sensorData} + {device.sensorData.humidity.toFixed(1)}% + {:else} + --% + {/if} +
- 1013 + + {#if deviceSensorData.get(device.id)?.pressure !== undefined} + {Math.round(deviceSensorData.get(device.id).pressure)}Pa + {:else if device.sensorData} + {Math.round(device.sensorData.pressure)}Pa + {:else} + --Pa + {/if} +
- 120m + + {#if deviceSensorData.get(device.id)?.altitude !== undefined} + {deviceSensorData.get(device.id).altitude.toFixed(1)}m + {:else if device.sensorData} + {device.sensorData.altitude.toFixed(1)}m + {:else} + --m + {/if} +
diff --git a/src/routes/(app)/settings/+page.server.js b/src/routes/(app)/settings/+page.server.js index f65e398..e7bdcb0 100644 --- a/src/routes/(app)/settings/+page.server.js +++ b/src/routes/(app)/settings/+page.server.js @@ -1,5 +1,6 @@ import { db } from "$lib/server/db"; import * as table from "$lib/server/db/schema"; +import { getCurrentDevices } from "$lib/server/mqtt-devices.js"; import { fail } from "@sveltejs/kit"; import { eq } from "drizzle-orm"; @@ -10,13 +11,20 @@ export const load = async (event) => { .from(table.floors) .orderBy(table.floors.floor); - // Provide mock ESP8266 devices for now - const devices = [ - { id: "esp8266-001", name: "ESP8266 #001", type: "esp8266", status: "online" }, - { id: "esp8266-002", name: "ESP8266 #002", type: "esp8266", status: "online" }, - { id: "esp8266-003", name: "ESP8266 #003", type: "esp8266", status: "offline" }, - { id: "esp8266-004", name: "ESP8266 #004", type: "esp8266", status: "online" }, - ]; + // Get real connected devices from MQTT + let devices = getCurrentDevices(); + + // If no real devices, provide fallback mock devices + if (devices.length === 0) { + devices = [ + { + id: "no-devices", + name: "No ESP8266 devices connected", + type: "esp8266", + status: "offline", + }, + ]; + } return { floors: floors.map((f) => f.floor), diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte index d8a8fb6..9b57069 100644 --- a/src/routes/(app)/settings/+page.svelte +++ b/src/routes/(app)/settings/+page.svelte @@ -1,5 +1,6 @@