From 42eb636f3ee7e2ece9d4fdf8e0af70099bf18aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Tue, 21 Jul 2026 18:19:10 +0400 Subject: [PATCH] =?UTF-8?q?Initial=20=E2=80=94=20Node.js=20IoT=20Dashboard?= =?UTF-8?q?=20with=20Chart.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 13 +++++ public/index.html | 130 ++++++++++++++++++++++++++++++++++++++++++++++ server.js | 65 +++++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 package.json create mode 100644 public/index.html create mode 100644 server.js diff --git a/package.json b/package.json new file mode 100644 index 0000000..04b9246 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "tf-iot-dashboard", + "version": "1.0.0", + "description": "IoT Dashboard — Node.js + Redis + Chart.js", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.21.0", + "redis": "^4.7.0" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..a1b1d2c --- /dev/null +++ b/public/index.html @@ -0,0 +1,130 @@ + + + + + + IoT Dashboard — Умный дом + + + + +
+

🏠 IoT Dashboard — Умный дом

+ Kafka → Redis → MongoDB | Автообновление каждые 3 сек +
+
+
+

📊 Последние значения датчиков

+
+
+
+

📈 Счётчики по типам устройств

+
+
+
+

📋 Последние события

+
+ + + +
ВремяДатчикЗначениеЛокация
+
+
+
+ + + + diff --git a/server.js b/server.js new file mode 100644 index 0000000..3270c31 --- /dev/null +++ b/server.js @@ -0,0 +1,65 @@ +const express = require("express"); +const { createClient } = require("redis"); + +const PORT = process.env.PORT || 3000; +const REDIS_HOST = process.env.REDIS_HOST || "127.0.0.1"; +const REDIS_PORT = parseInt(process.env.REDIS_PORT || "6379"); +const REDIS_PASSWORD = process.env.REDIS_PASSWORD || undefined; + +const app = express(); +app.use(express.static("public")); + +const redis = createClient({ + socket: { host: REDIS_HOST, port: REDIS_PORT }, + password: REDIS_PASSWORD, +}); + +redis.on("error", (err) => console.error("Redis error:", err.message)); + +async function start() { + await redis.connect(); + console.log("Redis connected"); + + // API: latest sensor values + app.get("/api/latest", async (req, res) => { + try { + const data = await redis.hGetAll("iot:latest"); + const items = Object.entries(data).map(([id, json]) => ({ + sensor_id: id, + ...JSON.parse(json), + })); + res.json(items); + } catch (e) { + res.json({ error: e.message }); + } + }); + + // API: counters by device type + app.get("/api/counters", async (req, res) => { + try { + const data = await redis.hGetAll("iot:counters"); + res.json(data); + } catch (e) { + res.json({ error: e.message }); + } + }); + + // API: recent events + app.get("/api/recent", async (req, res) => { + try { + const items = await redis.zRange("iot:recent", 0, 49, { REV: true }); + res.json(items.map(JSON.parse)); + } catch (e) { + res.json({ error: e.message }); + } + }); + + // Health check + app.get("/", (req, res) => { + res.send("IoT Dashboard OK"); + }); + + app.listen(PORT, () => console.log(`Dashboard on port ${PORT}`)); +} + +start();