Spaces:
Sleeping
Sleeping
| const express = require("express"); | |
| const http = require("http"); | |
| const app = express(); | |
| const server = http.createServer(app); | |
| // Store LED states | |
| let ledStates = { | |
| led1: false, | |
| led2: false, | |
| led3: false, | |
| led4: false, | |
| chase: false | |
| }; | |
| // Store SSE clients (ESP8266 devices) | |
| let sseClients = []; | |
| app.use(express.json()); | |
| app.use(express.static(".")); | |
| // SSE endpoint for ESP8266 | |
| app.get("/events", (req, res) => { | |
| res.setHeader("Content-Type", "text/event-stream"); | |
| res.setHeader("Cache-Control", "no-cache"); | |
| res.setHeader("Connection", "keep-alive"); | |
| res.setHeader("Access-Control-Allow-Origin", "*"); | |
| console.log("New SSE client connected"); | |
| // Send current state immediately | |
| Object.keys(ledStates).forEach(led => { | |
| const message = `data: ${led}:${ledStates[led] ? 1 : 0}\n\n`; | |
| res.write(message); | |
| console.log(`Sent initial state: ${led}:${ledStates[led] ? 1 : 0}`); | |
| }); | |
| // Add client to list | |
| sseClients.push(res); | |
| console.log(`Total ESP8266 clients: ${sseClients.length}`); | |
| // Send keepalive every 30 seconds | |
| const keepaliveInterval = setInterval(() => { | |
| try { | |
| res.write(`:keepalive\n\n`); | |
| } catch (err) { | |
| clearInterval(keepaliveInterval); | |
| } | |
| }, 30000); | |
| // Remove client on disconnect | |
| req.on("close", () => { | |
| clearInterval(keepaliveInterval); | |
| sseClients = sseClients.filter(client => client !== res); | |
| console.log(`ESP8266 disconnected. Total clients: ${sseClients.length}`); | |
| }); | |
| }); | |
| // Get current LED states (for frontend) | |
| app.get("/api/leds", (req, res) => { | |
| res.json(ledStates); | |
| }); | |
| // Get connection status | |
| app.get("/api/status", (req, res) => { | |
| res.json({ | |
| connected: sseClients.length > 0, | |
| clientCount: sseClients.length | |
| }); | |
| }); | |
| // Toggle individual LED (for frontend) | |
| app.post("/api/led/:ledName", (req, res) => { | |
| const { ledName } = req.params; | |
| const { state } = req.body; | |
| if (!ledStates.hasOwnProperty(ledName)) { | |
| return res.status(400).json({ error: "Invalid LED name" }); | |
| } | |
| ledStates[ledName] = state; | |
| // If turning on chase, turn off individual LEDs 1-3 | |
| if (ledName === "chase" && state) { | |
| ledStates.led1 = false; | |
| ledStates.led2 = false; | |
| ledStates.led3 = false; | |
| } | |
| // Broadcast to all ESP8266 devices via SSE | |
| const message = `data: ${ledName}:${state ? 1 : 0}\n\n`; | |
| console.log(`Broadcasting: ${ledName}:${state ? 1 : 0} to ${sseClients.length} clients`); | |
| sseClients.forEach((client, index) => { | |
| try { | |
| client.write(message); | |
| } catch (err) { | |
| console.error(`Error sending to client ${index}:`, err.message); | |
| } | |
| }); | |
| // If chase was turned on, also send LED1-3 off commands | |
| if (ledName === "chase" && state) { | |
| ["led1", "led2", "led3"].forEach(led => { | |
| const msg = `data: ${led}:0\n\n`; | |
| console.log(`Broadcasting: ${led}:0`); | |
| sseClients.forEach(client => { | |
| try { | |
| client.write(msg); | |
| } catch (err) { | |
| console.error("Error sending to client:", err.message); | |
| } | |
| }); | |
| }); | |
| } | |
| console.log(`${ledName} set to ${state ? "ON" : "OFF"}`); | |
| res.json({ success: true, ledStates }); | |
| }); | |
| // Turn all LEDs off | |
| app.post("/api/all-off", (req, res) => { | |
| Object.keys(ledStates).forEach(led => { | |
| ledStates[led] = false; | |
| const message = `data: ${led}:0\n\n`; | |
| console.log(`Broadcasting: ${led}:0`); | |
| sseClients.forEach(client => { | |
| try { | |
| client.write(message); | |
| } catch (err) { | |
| console.error("Error sending to client:", err.message); | |
| } | |
| }); | |
| }); | |
| console.log("All LEDs turned OFF"); | |
| res.json({ success: true, ledStates }); | |
| }); | |
| const PORT = process.env.PORT || 3000; | |
| const HOST = "0.0.0.0"; | |
| server.listen(PORT, HOST, () => { | |
| console.log(`\n=================================`); | |
| console.log(`Server running at http://${HOST}:${PORT}`); | |
| console.log(`SSE endpoint: http://${HOST}:${PORT}/events`); | |
| console.log(`API endpoint: http://${HOST}:${PORT}/api/leds`); | |
| console.log(`=================================\n`); | |
| }); |