Iot / server.js
veltrixcode's picture
Update server.js
2dca8eb verified
Raw
History Blame Contribute Delete
4.06 kB
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`);
});