From ac2e27cf6a3fe12ceb06786000786b454a287660 Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Tue, 31 Oct 2023 16:27:41 +0300 Subject: [PATCH] progress --- controllers/modbus.controller.js | 18 +++-- data.db | Bin 20480 -> 20480 bytes migrations/001-init.sql | 22 +++--- public/css/dist.css | 12 ++++ public/index.html | 120 +++++++++++++++++++------------ public/js/app.js | 31 +++++--- 6 files changed, 135 insertions(+), 68 deletions(-) diff --git a/controllers/modbus.controller.js b/controllers/modbus.controller.js index 8deb5c9..708ccde 100644 --- a/controllers/modbus.controller.js +++ b/controllers/modbus.controller.js @@ -208,6 +208,7 @@ export const modbusController = { if (!req.query.slave_id) return res.status(400).json({ error: { message: "'slave_id' parameter is required." } }); const device = await db.get(`SELECT * FROM "modbus_slaves" WHERE id = ?`, [req.query.slave_id]); + const displayValues = await db.all(`SELECT * FROM "display_values" WHERE slave_id = ?`, [req.query.slave_id]) if (!device) return res.status(404).json({ error: { message: "Device not found." } }); @@ -216,8 +217,12 @@ export const modbusController = { res.setHeader("Connection", "keep-alive"); let interval = setInterval(async () => { - let value = 0; - let len = 1; // 16 bits default + let graphValue = 0; + let len = 1; // 16 bits default + + for (const value of displayValues) { + value.data = Buffer.from((await modbusClient.readHoldingRegisters(value.reg_addr, 1)).buffer).readUInt16BE(); + } if (device.g_display_reg_format === 32) len = 2; // ...64, 128, 256... @@ -226,17 +231,20 @@ export const modbusController = { switch (device.g_display_reg_format) { case 32: - value = Buffer.from(result.buffer).readUInt32BE(); + graphValue = Buffer.from(result.buffer).readUInt32BE(); break; case 16: - value = Buffer.from(result.buffer).readUint16BE(); + graphValue = Buffer.from(result.buffer).readUint16BE(); break; default: break; } res.write("event: message\n"); - res.write(`data: ${JSON.stringify({ graph: { value, format: device.g_display_reg_format } })}\n\n`); + res.write(`data: ${JSON.stringify({ + graph: { value: graphValue, format: device.g_display_reg_format }, + displayValues + })}\n\n`); }, 1000); req.on("close", () => clearInterval(interval)); } catch (error) { diff --git a/data.db b/data.db index 84155ce5f9d09ad55b3bd3f2ebbdc52283e74b97..78ab51f34c4a8a080d5aabb01cbe6e5c70c70884 100644 GIT binary patch delta 468 zcmYL^J4*vW5XX1#^17F^X9$UjNzRC%aLDZiO<@^JAweY|Hbyx?2(b{f(+FanuoA3% zAfyQvA$E%R0rCk%EK-P_g<$POIGmkXX8yn3VWx3I8#lC>GKYkaAck*)mYt`=-c|1LoDtM1tEEU!1cIRhiA(R&K4F zLjhehGl?We$)^iQixn5KJHjuSc#@;$ZcJ>XYd zGMFmkLuJ%MXPSfrbDUaZ8ubgVG6UzJ@J7)8tv~5JL947S=7>h3S;>%MRFT$;W$qT{ z9Xy==%rxrzbuS`+jyeS3lHeW#+~E?=`%~5tjEzSLHR5&ei0xKu2cliFQ!-nrZhJK= XpOC^NtI(9P>>cjyc-FKl-b=Y(AcS0) delta 518 zcmYk2&r2IY6vyYyX0w_6@XZ=xTCB+$@fR#%ccWG*J*5|=kcCLD{@g=AA_UDzXzX90 zOd&ZHFA5%n%J!<{F7(_(>9Kg~sr1|z?TU{#1Ml(W3lDaeI6?A6eDNuUxVkCiUl57J*H25dp?(+g zf(VIkGD&*nXLVIv&*MEau+Q)h{=jcIz!1-|kNwbey7(cLh%*xa>b_>kv=L`n8mbLf zi_26zlDIC@dL(%~CeyKKa=9jx8X3hfgG>6wbXEw8@MIFmB@)9pnIQr2JEMMHVZph@ zw?t-Gie+bchUY-=^{Vf#cx88Kx$Kl(rviVcyRH3JkkIajIWg=p{DpV;1$%fLPFigo y9m@llx!s`C3Apqd2kk@EtJ$v-^8MC!uxC|Xa)T8C#>Km!)7%NHDUYk4wbDOCd}Lk# diff --git a/migrations/001-init.sql b/migrations/001-init.sql index d1df254..822f187 100644 --- a/migrations/001-init.sql +++ b/migrations/001-init.sql @@ -58,22 +58,22 @@ CREATE TABLE IF NOT EXISTS "display_values" ( INSERT INTO "modbus_slaves" ( "id", "name", "g_display_reg_addr", "g_display_reg_format", "g_y_label", "is_logging" ) VALUES - (1, "Device #1", 1, 16, "Label 1", 1), - (2, "Device #2", 2, 32, "Label 2", 1), - (3, "Device #3", 8, 16, "Label 3", 0), + (1, "Device #1", 0, 16, "Label 1", 1), + (2, "Device #2", 1, 32, "Label 2", 1), + (3, "Device #3", 3, 16, "Label 3", 0), (4, "Device #4", NULL, NULL, "Label 4", 0); INSERT INTO "display_values" ( "id", "name", "slave_id", "reg_addr", "reg_format" ) VALUES - (1, "CV1", 1, 0, 16), - (2, "CV2", 1, 1, 16), - (3, "SP", 1, 2, 16), - (4, "CV1", 2, 3, 16), - (5, "CV2", 2, 4, 16), - (6, "SP", 2, 5, 16), - (7, "CV1", 3, 6, 16), - (8, "SP", 3, 7, 16); + (1, "CV1", 1, 10, 16), + (2, "CV2", 1, 11, 16), + (3, "SP", 1, 12, 16), + (4, "CV1", 2, 13, 16), + (5, "CV2", 2, 14, 16), + (6, "SP", 2, 15, 16), + (7, "CV1", 3, 16, 16), + (8, "SP", 3, 17, 16); -------------------------------------------------------------------------------- -- Down -------------------------------------------------------------------------------- diff --git a/public/css/dist.css b/public/css/dist.css index c43c182..ac86915 100644 --- a/public/css/dist.css +++ b/public/css/dist.css @@ -698,6 +698,10 @@ video { margin-top: 1.5rem; } +.mt-auto { + margin-top: auto; +} + .block { display: block; } @@ -726,6 +730,10 @@ video { height: 5rem; } +.h-\[720px\] { + height: 720px; +} + .h-full { height: 100%; } @@ -734,6 +742,10 @@ video { height: 100vh; } +.h-\[300px\] { + height: 300px; +} + .max-h-\[400px\] { max-height: 400px; } diff --git a/public/index.html b/public/index.html index 20842c2..45531e9 100644 --- a/public/index.html +++ b/public/index.html @@ -135,7 +135,6 @@

- ID:
@@ -152,57 +151,90 @@
+ + -
+
+
+ Register: + Format: +

+
+
+
+ +
+

Loading...

+
+
-

Display values

-
-
- -
- +
diff --git a/public/js/app.js b/public/js/app.js index 712512e..ea55f0a 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -5,7 +5,7 @@ import * as utils from "./utils/index.js"; var pages = ["loading", "monitoring", "configuration", "404"]; var dataStreamSource; -var graphData = [[0, 0]]; +var graphData = [[0,0]]; var g; document.addEventListener("alpine:init", async () => { @@ -106,14 +106,17 @@ document.addEventListener("alpine:init", async () => { Alpine.data("monitoringPage", () => ({ selectedDevice: null, devices: [], + isLoading: false, + error: null, + resetGraph() { + if (g instanceof Dygraph) { + g.destroy(); + } + }, async init() { try { this.$store.app.currentPage = "loading"; this.devices = await api.get("/modbus/devices"); - // window.intervalId = setInterval(() => { - // graphData.push([new Date(), Math.random()]); - // g.updateOptions({ file: graphData }); - // }, 500); } catch (error) { this.$store.app.error = error; } finally { @@ -121,6 +124,14 @@ document.addEventListener("alpine:init", async () => { } }, selectDevice(device) { + if (device.id === this.selectedDevice?.id) return; + + this.selectedDevice = device; + this.resetGraph(); + + // if (device.g_display_reg_addr !== null) + this.isLoading = true; + dataStreamSource?.close(); dataStreamSource = new EventSource(`/api/modbus/data_stream?slave_id=${device.id}`); g = new Dygraph(document.getElementById("div_g"), graphData, { @@ -130,15 +141,19 @@ document.addEventListener("alpine:init", async () => { // valueRange: [0, 1000], // labels: ["Time", "Random"], }); + g.resize(720, 300); + dataStreamSource.onerror = (e) => { + dataStreamSource.close(); + } dataStreamSource.onmessage = (e) => { const data = JSON.parse(e.data); console.log(data); graphData.push([new Date(), data.graph.value]); g.updateOptions({ file: graphData }); + data.displayValues.forEach((v, i) => this.selectedDevice.display_values[i] = v); + this.isLoading = false; }; - if (device.id === this.selectedDevice?.id) return; - graphData = []; // todo: reset graph - this.selectedDevice = device; + graphData = []; }, async removeDevice(id) { try {