remove unused imports

This commit is contained in:
David Senoner 2025-06-15 14:23:16 +02:00
parent b57d9b7875
commit b8b0f2d6a1
Signed by: kada49
GPG key ID: 92BABE6B7E63C6CA
8 changed files with 15 additions and 98 deletions

View file

@ -1,15 +1,8 @@
// 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 connectedDevices = new Map();
let deviceSensorData = new Map(); let deviceSensorData = new Map();
// Export the maps so the MQTT server can set them
export { connectedDevices, deviceSensorData }; export { connectedDevices, deviceSensorData };
// Clean up offline devices (not seen in last 5 minutes)
function cleanupDevices() { function cleanupDevices() {
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
let updated = false; let updated = false;
@ -24,7 +17,6 @@ function cleanupDevices() {
return updated; return updated;
} }
// Export function to get current devices
export function getCurrentDevices() { export function getCurrentDevices() {
cleanupDevices(); cleanupDevices();
return Array.from(connectedDevices.values()).map((device) => { return Array.from(connectedDevices.values()).map((device) => {
@ -36,7 +28,6 @@ export function getCurrentDevices() {
}); });
} }
// Export function to get sensor data for a specific device
export function getDeviceSensorData(deviceId) { export function getDeviceSensorData(deviceId) {
return deviceSensorData.get(deviceId) || null; return deviceSensorData.get(deviceId) || null;
} }

View file

@ -2,14 +2,11 @@ import { db } from "$lib/server/db";
import * as table from "$lib/server/db/schema"; import * as table from "$lib/server/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import type { PageServerLoad } from "./$types"; import type { PageServerLoad } from "./$types";
import { connect } from "mqtt";
import { getDeviceSensorData } from "$lib/server/mqtt-devices.js"; import { getDeviceSensorData } from "$lib/server/mqtt-devices.js";
export const load: PageServerLoad = async ({ params }) => { export const load: PageServerLoad = async ({ params }) => {
// Convert slug to number for floor lookup
const floorNumber = Number(params.slug); const floorNumber = Number(params.slug);
// First check if we have a saved floor configuration in the floors table
const floorData = await db.select({ const floorData = await db.select({
floor: table.floors.floor, floor: table.floors.floor,
url: table.floors.url url: table.floors.url
@ -17,10 +14,8 @@ export const load: PageServerLoad = async ({ params }) => {
if (floorData.length > 0 && floorData[0].url && floorData[0].url !== "/") { if (floorData.length > 0 && floorData[0].url && floorData[0].url !== "/") {
try { try {
// Try to parse the saved configuration
const config = JSON.parse(floorData[0].url); const config = JSON.parse(floorData[0].url);
// Add real sensor data to devices
if (config.devices) { if (config.devices) {
config.devices = config.devices.map(device => { config.devices = config.devices.map(device => {
const sensorData = getDeviceSensorData(device.id); const sensorData = getDeviceSensorData(device.id);
@ -41,7 +36,6 @@ export const load: PageServerLoad = async ({ params }) => {
} }
} }
// Fallback to the old canvas drawing system
const floor_cnt = await db.select({ floor: table.plans.floor, json: table.plans.plan }).from(table.plans).where(eq(table.plans.floor, params.slug)); const floor_cnt = await db.select({ floor: table.plans.floor, json: table.plans.plan }).from(table.plans).where(eq(table.plans.floor, params.slug));
if (floor_cnt.length == 0) { if (floor_cnt.length == 0) {
await db.insert(table.plans).values({ floor: params.slug, plan: { await db.insert(table.plans).values({ floor: params.slug, plan: {

View file

@ -14,7 +14,6 @@
let refreshInterval; let refreshInterval;
onMount(() => { onMount(() => {
// Connect to the SSE endpoint
console.log("Attempting to connect to MQTT SSE..."); console.log("Attempting to connect to MQTT SSE...");
eventSource = new EventSource("/mqtt"); eventSource = new EventSource("/mqtt");
@ -32,7 +31,6 @@
const messageData = JSON.parse(event.data); const messageData = JSON.parse(event.data);
console.log("Floor page received SSE data:", messageData); console.log("Floor page received SSE data:", messageData);
// Handle device updates
if (messageData.devices) { if (messageData.devices) {
console.log("Received devices:", messageData.devices); console.log("Received devices:", messageData.devices);
const newData = new Map(); const newData = new Map();
@ -46,7 +44,6 @@
console.log("Updated deviceSensorData:", deviceSensorData); console.log("Updated deviceSensorData:", deviceSensorData);
} }
// Handle MQTT message if present
if (messageData.message) { if (messageData.message) {
mqttMessage = messageData.message; mqttMessage = messageData.message;
} else { } else {
@ -59,7 +56,7 @@
eventSource.onerror = (error) => { eventSource.onerror = (error) => {
console.error("SSE Error:", error); console.error("SSE Error:", error);
eventSource.close(); // Close the connection on error eventSource.close();
}; };
}); });
@ -82,7 +79,6 @@
return; return;
} }
// Draw walls, doors, and furniture (simplified example)
drawRegions(data.regions); drawRegions(data.regions);
drawDoors(data.doors); drawDoors(data.doors);
drawFurniture(data.furnitures); drawFurniture(data.furnitures);
@ -100,7 +96,7 @@
function drawDoors(doors) { function drawDoors(doors) {
doors.forEach((door) => { doors.forEach((door) => {
ctx.beginPath(); ctx.beginPath();
ctx.rect(door.location.x, door.location.y, door.width, 5); // Simplified door drawing ctx.rect(door.location.x, door.location.y, door.width, 5);
ctx.stroke(); ctx.stroke();
}); });
} }
@ -455,7 +451,6 @@
<Card.Content> <Card.Content>
<div class="space-y-4"> <div class="space-y-4">
{#if filteredData.length > 0} {#if filteredData.length > 0}
<!-- Statistics Summary -->
<div class="grid grid-cols-3 gap-4 rounded border p-4 text-center"> <div class="grid grid-cols-3 gap-4 rounded border p-4 text-center">
<div> <div>
<div class="text-muted-foreground text-sm font-medium">Latest</div> <div class="text-muted-foreground text-sm font-medium">Latest</div>
@ -497,10 +492,8 @@
</div> </div>
</div> </div>
<!-- Simple SVG Line Chart -->
<div class="rounded border bg-white p-4"> <div class="rounded border bg-white p-4">
<svg viewBox="0 0 800 400" class="h-80 w-full"> <svg viewBox="0 0 800 400" class="h-80 w-full">
<!-- Chart area -->
{#if filteredData.length > 1} {#if filteredData.length > 1}
{@const minValue = Math.min(...filteredData.map((d) => d[selectedSensor]))} {@const minValue = Math.min(...filteredData.map((d) => d[selectedSensor]))}
{@const maxValue = Math.max(...filteredData.map((d) => d[selectedSensor]))} {@const maxValue = Math.max(...filteredData.map((d) => d[selectedSensor]))}
@ -509,7 +502,6 @@
{@const chartWidth = 800 - padding * 2} {@const chartWidth = 800 - padding * 2}
{@const chartHeight = 400 - padding * 2} {@const chartHeight = 400 - padding * 2}
<!-- Background grid -->
<defs> <defs>
<pattern id="grid" width="50" height="40" patternUnits="userSpaceOnUse"> <pattern id="grid" width="50" height="40" patternUnits="userSpaceOnUse">
<path <path
@ -528,7 +520,6 @@
fill="url(#grid)" fill="url(#grid)"
/> />
<!-- Y-axis labels -->
<text x="25" y={padding + 5} class="fill-gray-600 text-xs" text-anchor="end" <text x="25" y={padding + 5} class="fill-gray-600 text-xs" text-anchor="end"
>{maxValue.toFixed(1)}</text >{maxValue.toFixed(1)}</text
> >
@ -545,14 +536,12 @@
text-anchor="end">{minValue.toFixed(1)}</text text-anchor="end">{minValue.toFixed(1)}</text
> >
<!-- X-axis labels -->
{#if filteredData.length > 0} {#if filteredData.length > 0}
{@const firstDate = filteredData[0].date} {@const firstDate = filteredData[0].date}
{@const lastDate = filteredData[filteredData.length - 1].date} {@const lastDate = filteredData[filteredData.length - 1].date}
{@const midIndex = Math.floor(filteredData.length / 2)} {@const midIndex = Math.floor(filteredData.length / 2)}
{@const midDate = filteredData[midIndex].date} {@const midDate = filteredData[midIndex].date}
<!-- Format dates based on time range -->
{@const formatDate = (date) => { {@const formatDate = (date) => {
if (timeRange === "7d") { if (timeRange === "7d") {
return date.toLocaleDateString("en-US", { return date.toLocaleDateString("en-US", {
@ -590,7 +579,6 @@
> >
{/if} {/if}
<!-- Data line -->
<polyline <polyline
fill="none" fill="none"
stroke="#3b82f6" stroke="#3b82f6"

View file

@ -3,7 +3,6 @@ import * as table from "$lib/server/db/schema"
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
export const GET = async (event) => { export const GET = async (event) => {
// Get all sensor data (like the original working version)
console.log(event.locals.session.userId) console.log(event.locals.session.userId)
const rawData = await db.select({ const rawData = await db.select({
altitude: table.sensorData.altitude, altitude: table.sensorData.altitude,
@ -15,11 +14,9 @@ export const GET = async (event) => {
user: table.sensors.user, user: table.sensors.user,
}).from(table.sensorData).innerJoin(table.sensors, eq(table.sensors.id, table.sensorData.sensor)).where(eq(table.sensors.user, event.locals.session.userId)); }).from(table.sensorData).innerJoin(table.sensors, eq(table.sensors.id, table.sensorData.sensor)).where(eq(table.sensors.user, event.locals.session.userId));
// Scale pressure values to be in a similar range as other sensors
// Divide by 1000 to convert from Pa to kPa (more reasonable scale)
const data = rawData.map(item => ({ const data = rawData.map(item => ({
...item, ...item,
pressure: Math.round((item.pressure / 1000) * 10) / 10 // Convert to kPa with 1 decimal place pressure: Math.round((item.pressure / 1000) * 10) / 10
})); }));
console.log(`Returning ${data.length} data points`); console.log(`Returning ${data.length} data points`);

View file

@ -5,16 +5,13 @@ import { fail } from "@sveltejs/kit";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
export const load = async (event) => { export const load = async (event) => {
// Fetch all available floors
const floors = await db const floors = await db
.select({ floor: table.floors.floor }) .select({ floor: table.floors.floor })
.from(table.floors) .from(table.floors)
.orderBy(table.floors.floor); .orderBy(table.floors.floor);
// Get real connected devices from MQTT
let devices = getCurrentDevices(); let devices = getCurrentDevices();
// If no real devices, provide fallback mock devices
if (devices.length === 0) { if (devices.length === 0) {
devices = [ devices = [
{ {
@ -85,7 +82,6 @@ export const actions = {
await db.insert(table.sensors).values({ id: dev.id, user: event.locals.session.userId }); await db.insert(table.sensors).values({ id: dev.id, user: event.locals.session.userId });
}); });
// Check if floor exists
const exists = await db const exists = await db
.select({ floor: table.floors.floor }) .select({ floor: table.floors.floor })
.from(table.floors) .from(table.floors)
@ -95,9 +91,6 @@ export const actions = {
return fail(400, { message: `Floor ${n} does not exist! Please create it first.` }); return fail(400, { message: `Floor ${n} does not exist! Please create it first.` });
} }
// Update floor with configuration
// Note: In a real implementation, you would store this data properly
// For now, we'll just update the url field as a JSON string
const floorConfig = { const floorConfig = {
image: floorPlanImage, image: floorPlanImage,
devices: deviceData, devices: deviceData,

View file

@ -31,13 +31,11 @@
}); });
$effect(() => { $effect(() => {
// Update devices when data changes
if (data.devices) { if (data.devices) {
availableDevices = data.devices; availableDevices = data.devices;
} }
}); });
// Set up real-time updates via SSE
onMount(() => { onMount(() => {
console.log("Settings: Attempting to connect to MQTT SSE..."); console.log("Settings: Attempting to connect to MQTT SSE...");
eventSource = new EventSource("/mqtt"); eventSource = new EventSource("/mqtt");
@ -56,13 +54,10 @@
const messageData = JSON.parse(event.data); const messageData = JSON.parse(event.data);
console.log("Settings page received SSE data:", messageData); console.log("Settings page received SSE data:", messageData);
// Update device sensor data and device list from real-time updates
if (messageData.devices) { if (messageData.devices) {
console.log("Updating available devices with:", messageData.devices); console.log("Updating available devices with:", messageData.devices);
// Update available devices with latest data
availableDevices = messageData.devices; availableDevices = messageData.devices;
// Update sensor data map
const newData = new Map(); const newData = new Map();
messageData.devices.forEach((device) => { messageData.devices.forEach((device) => {
if (device.sensorData) { if (device.sensorData) {
@ -116,14 +111,11 @@
const x = ((event.clientX - rect.left) / rect.width) * 100; const x = ((event.clientX - rect.left) / rect.width) * 100;
const y = ((event.clientY - rect.top) / rect.height) * 100; const y = ((event.clientY - rect.top) / rect.height) * 100;
// Check if device is already placed
const existingIndex = placedDevices.findIndex((d) => d.id === draggedDevice.id); const existingIndex = placedDevices.findIndex((d) => d.id === draggedDevice.id);
if (existingIndex >= 0) { if (existingIndex >= 0) {
// Update position
placedDevices[existingIndex] = { ...placedDevices[existingIndex], x, y }; placedDevices[existingIndex] = { ...placedDevices[existingIndex], x, y };
} else { } else {
// Add new device
placedDevices = [...placedDevices, { ...draggedDevice, x, y }]; placedDevices = [...placedDevices, { ...draggedDevice, x, y }];
} }
@ -244,7 +236,6 @@
return async ({ result }) => { return async ({ result }) => {
if (result.type === "success") { if (result.type === "success") {
saveMessage = { type: "success", text: result.data.message }; saveMessage = { type: "success", text: result.data.message };
// Clear form after successful save
selectedFloorNumber = ""; selectedFloorNumber = "";
} else if (result.type === "failure") { } else if (result.type === "failure") {
saveMessage = { saveMessage = {

View file

@ -63,7 +63,6 @@ export const actions = {
const userId = generateUserId(); const userId = generateUserId();
const passwordHash = await hash(password, { const passwordHash = await hash(password, {
// recommended minimum parameters
memoryCost: 19456, memoryCost: 19456,
timeCost: 2, timeCost: 2,
outputLen: 32, outputLen: 32,
@ -84,7 +83,6 @@ export const actions = {
}; };
function generateUserId() { function generateUserId() {
// ID with 120 bits of entropy, or about the same as UUID v4.
const bytes = crypto.getRandomValues(new Uint8Array(15)); const bytes = crypto.getRandomValues(new Uint8Array(15));
const id = encodeBase64url(bytes); const id = encodeBase64url(bytes);
return id; return id;

View file

@ -1,4 +1,3 @@
// src/routes/mqtt/+server.js
import { db } from "$lib/server/db"; import { db } from "$lib/server/db";
import * as table from "$lib/server/db/schema"; import * as table from "$lib/server/db/schema";
import { connectedDevices, deviceSensorData, getCurrentDevices } from "$lib/server/mqtt-devices.js"; import { connectedDevices, deviceSensorData, getCurrentDevices } from "$lib/server/mqtt-devices.js";
@ -6,20 +5,15 @@ import { eq } from "drizzle-orm";
import mqtt from "mqtt"; import mqtt from "mqtt";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
// A Svelte store to hold the latest MQTT message.
// In a real application, you might want to store more data or
// use a more robust way to manage messages, but for a basic example, this works.
const latestMessage = writable("No message yet"); const latestMessage = writable("No message yet");
const devices = writable([]); const devices = writable([]);
let client = null; let client = null;
// Function to update device status and sensor data
function updateDevice(deviceId, sensorData = null) { function updateDevice(deviceId, sensorData = null) {
const now = new Date(); const now = new Date();
const deviceName = `ESP8266 #${deviceId.slice(-6)}`; const deviceName = `ESP8266 #${deviceId.slice(-6)}`;
// Update device info
connectedDevices.set(deviceId, { connectedDevices.set(deviceId, {
id: deviceId, id: deviceId,
name: deviceName, name: deviceName,
@ -28,7 +22,6 @@ function updateDevice(deviceId, sensorData = null) {
lastSeen: now, lastSeen: now,
}); });
// Update sensor data if provided
if (sensorData) { if (sensorData) {
deviceSensorData.set(deviceId, { deviceSensorData.set(deviceId, {
...sensorData, ...sensorData,
@ -36,11 +29,9 @@ function updateDevice(deviceId, sensorData = null) {
}); });
} }
// Update the devices store
updateDevicesStore(); updateDevicesStore();
} }
// Function to parse sensor data from MQTT payload
function parseSensorData(payload) { function parseSensorData(payload) {
try { try {
const data = JSON.parse(payload); const data = JSON.parse(payload);
@ -56,10 +47,8 @@ function parseSensorData(payload) {
} }
} }
// Store SSE controllers for cleanup
const sseControllers = new Set(); const sseControllers = new Set();
// Function to update devices store with latest data
function updateDevicesStore() { function updateDevicesStore() {
const deviceList = Array.from(connectedDevices.values()).map((device) => { const deviceList = Array.from(connectedDevices.values()).map((device) => {
const sensorData = deviceSensorData.get(device.id); const sensorData = deviceSensorData.get(device.id);
@ -71,7 +60,6 @@ function updateDevicesStore() {
devices.set(deviceList); devices.set(deviceList);
} }
// Clean up offline devices (not seen in last 5 minutes)
function cleanupDevices() { function cleanupDevices() {
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
let updated = false; let updated = false;
@ -88,21 +76,15 @@ function cleanupDevices() {
} }
} }
// Run cleanup every minute
setInterval(cleanupDevices, 60000); setInterval(cleanupDevices, 60000);
// getCurrentDevices is now imported from the shared module
// Function to connect to MQTT
function connectMqtt() { function connectMqtt() {
if (client && client.connected) { if (client && client.connected) {
return; // Already connected return;
} }
// Replace with your MQTT broker details const BROKER_URL = "mqtt://kada49.it:1883";
const BROKER_URL = "mqtt://kada49.it:1883"; // Example public broker const TOPIC = "esp8266/+/data";
//const BROKER_URL = "mqtt://test.mosquitto.org:1883";
const TOPIC = "esp8266/+/data"; // Replace with your desired topic
client = mqtt.connect(BROKER_URL); client = mqtt.connect(BROKER_URL);
@ -120,32 +102,27 @@ function connectMqtt() {
client.on("message", async (topic, message) => { client.on("message", async (topic, message) => {
const payload = message.toString(); const payload = message.toString();
console.log(`Received message from topic "${topic}": ${payload}`); console.log(`Received message from topic "${topic}": ${payload}`);
latestMessage.set(payload); // Update the Svelte store latestMessage.set(payload);
// Extract device ID from topic (esp8266/DEVICE_ID/data)
const topicParts = topic.split("/"); const topicParts = topic.split("/");
if (topicParts.length >= 3 && topicParts[0] === "esp8266" && topicParts[2] === "data") { if (topicParts.length >= 3 && topicParts[0] === "esp8266" && topicParts[2] === "data") {
const deviceId = topicParts[1]; const deviceId = topicParts[1];
console.log(`Processing data for device: ${deviceId}`); console.log(`Processing data for device: ${deviceId}`);
// Parse sensor data
const sensorData = parseSensorData(payload); const sensorData = parseSensorData(payload);
if (sensorData) { if (sensorData) {
console.log(`Parsed sensor data:`, sensorData); console.log(`Parsed sensor data:`, sensorData);
updateDevice(deviceId, sensorData); updateDevice(deviceId, sensorData);
const devices = await db.select().from(table.sensors).where(eq(table.sensors.id, deviceId)); const devices = await db.select().from(table.sensors).where(eq(table.sensors.id, deviceId));
if (devices.length == 1) if (devices.length == 1)
await db await db.insert(table.sensorData).values({
.insert(table.sensorData) sensor: deviceId,
.values({ temperature: sensorData.temperature,
sensor: deviceId, humidity: sensorData.humidity,
temperature: sensorData.temperature, altitude: sensorData.altitude,
humidity: sensorData.humidity, pressure: sensorData.pressure,
altitude: sensorData.altitude, });
pressure: sensorData.pressure,
});
} else { } else {
// Still update device as online even if data parsing failed
updateDevice(deviceId); updateDevice(deviceId);
} }
} }
@ -154,20 +131,17 @@ function connectMqtt() {
client.on("error", (err) => { client.on("error", (err) => {
console.error(`MQTT error: ${err}`); console.error(`MQTT error: ${err}`);
if (client) { if (client) {
client.end(); // Close connection on error client.end();
} }
client = null; client = null;
// Implement re-connection logic here if needed
}); });
client.on("close", () => { client.on("close", () => {
console.log("MQTT connection closed."); console.log("MQTT connection closed.");
client = null; client = null;
// Implement re-connection logic here if needed
}); });
} }
// Connect to MQTT when the server starts
connectMqtt(); connectMqtt();
/** @type {import("./$types").RequestHandler} */ /** @type {import("./$types").RequestHandler} */
@ -186,10 +160,8 @@ export async function GET({ request }) {
let isConnected = true; let isConnected = true;
let interval; let interval;
// Add this controller to the broadcast set
sseControllers.add(controller); sseControllers.add(controller);
// Cleanup function
const cleanup = () => { const cleanup = () => {
console.log("Cleaning up MQTT SSE connection"); console.log("Cleaning up MQTT SSE connection");
isConnected = false; isConnected = false;
@ -203,7 +175,6 @@ export async function GET({ request }) {
} }
}; };
// Send current device data
function sendDevices() { function sendDevices() {
if (!isConnected) { if (!isConnected) {
cleanup(); cleanup();
@ -217,12 +188,10 @@ export async function GET({ request }) {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}; };
// Check if controller is still valid before enqueueing
if (isConnected) { if (isConnected) {
controller.enqueue(`data: ${JSON.stringify(message)}\n\n`); controller.enqueue(`data: ${JSON.stringify(message)}\n\n`);
} }
} catch (error) { } catch (error) {
// Handle controller closed error specifically
if ( if (
error.code === "ERR_INVALID_STATE" || error.code === "ERR_INVALID_STATE" ||
error.message.includes("Controller is already closed") error.message.includes("Controller is already closed")
@ -235,13 +204,10 @@ export async function GET({ request }) {
} }
} }
// Send initial data
sendDevices(); sendDevices();
// Send updates every 2 seconds
interval = setInterval(sendDevices, 2000); interval = setInterval(sendDevices, 2000);
// Subscribe to MQTT messages via the store for real-time updates
const unsubscribe = latestMessage.subscribe((message) => { const unsubscribe = latestMessage.subscribe((message) => {
if (message !== "No message yet" && isConnected) { if (message !== "No message yet" && isConnected) {
try { try {
@ -265,7 +231,6 @@ export async function GET({ request }) {
} }
}); });
// Handle client disconnection
request.signal.addEventListener("abort", () => { request.signal.addEventListener("abort", () => {
console.log("Client disconnected from MQTT SSE stream"); console.log("Client disconnected from MQTT SSE stream");
cleanup(); cleanup();