diff --git a/acs-visualiser/package-lock.json b/acs-visualiser/package-lock.json index a5e86ad0..4932b70f 100644 --- a/acs-visualiser/package-lock.json +++ b/acs-visualiser/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.3", "license": "ISC", "dependencies": { - "@amrc-factoryplus/service-client": "^1.3.4", + "@amrc-factoryplus/service-client": "^1.3.6", "express": "^4.18.1", "process": "^0.11.10", "tailwindcss": "^3.4.1", @@ -38,9 +38,10 @@ } }, "node_modules/@amrc-factoryplus/service-client": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@amrc-factoryplus/service-client/-/service-client-1.3.4.tgz", - "integrity": "sha512-Imefl969tcgNUh4+hOy9cCAJ4iq8cLTV+Ki/NQ4yfiO/a1pQBdy88HLdqn1ovA0TbQk6aOFn2BfqA8eNInunLg==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@amrc-factoryplus/service-client/-/service-client-1.3.6.tgz", + "integrity": "sha512-4t+/SDJwoqdY+5D2DIiF/xnB2RGjG3IIzy7qxewHVCBIJ8Q2CUEZlwt5ayts9mGmM/LHsQw9NHKes664tPqyYQ==", + "license": "ISC", "dependencies": { "content-type": "^1.0.5", "mqtt": "^5.3.6", @@ -5023,9 +5024,9 @@ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" }, "@amrc-factoryplus/service-client": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@amrc-factoryplus/service-client/-/service-client-1.3.4.tgz", - "integrity": "sha512-Imefl969tcgNUh4+hOy9cCAJ4iq8cLTV+Ki/NQ4yfiO/a1pQBdy88HLdqn1ovA0TbQk6aOFn2BfqA8eNInunLg==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@amrc-factoryplus/service-client/-/service-client-1.3.6.tgz", + "integrity": "sha512-4t+/SDJwoqdY+5D2DIiF/xnB2RGjG3IIzy7qxewHVCBIJ8Q2CUEZlwt5ayts9mGmM/LHsQw9NHKes664tPqyYQ==", "requires": { "content-type": "^1.0.5", "got-fetch": "^5.1.8", diff --git a/acs-visualiser/public/mqttclient.js b/acs-visualiser/public/mqttclient.js index 3315f004..8509fa75 100644 --- a/acs-visualiser/public/mqttclient.js +++ b/acs-visualiser/public/mqttclient.js @@ -15,6 +15,8 @@ export default class MQTTClient extends EventEmitter { this.graph = opts.graph; this.known = new Map(); + + this.utf8decoder = new TextDecoder(); } static graph (name) { @@ -57,9 +59,8 @@ export default class MQTTClient extends EventEmitter { const parts = [...group.split("-"), node]; if (device != undefined) parts.push(device); - const path = parts.join("/"); - - const graph = this.add_to_graph(parts, path); + + const graph = this.add_to_graph(parts); if (kind == "BIRTH" || kind == "DATA") { for (let g = graph; g; g = g.parent) g.online = true; @@ -81,11 +82,22 @@ export default class MQTTClient extends EventEmitter { graph.seen_data = true; delete graph.expires; } - - this.emit("packet", path, kind); + if (kind == "CMD") { + const sender = this.find_sender(message); + const from_parts = [...parts, sender]; + const cmd_from = this.add_to_graph(from_parts); + cmd_from.expires = Date.now() + 7.5*1000; + cmd_from.is_cmd = true; + this.emit("packet", cmd_from.path, kind, true); + } + else { + this.emit("packet", graph.path, kind, false); + } } - add_to_graph (parts, path) { + add_to_graph (parts) { + const path = parts.join("/"); + if (this.known.has(path)) return this.known.get(path); @@ -123,6 +135,15 @@ export default class MQTTClient extends EventEmitter { this.emit("schema", schema); } + find_sender (message) { + const payload = SpB.decodePayload(message); + if (payload.uuid != FactoryPlus) + return ''; + const decoded = this.utf8decoder.decode(payload.body); + const node_name = decoded.split(':') + return node_name[1]; + } + async check_directory (address, node) { if (node.seen_birth || node.checked_directory) return; diff --git a/acs-visualiser/public/packet.js b/acs-visualiser/public/packet.js index 6edecd91..9d5d5c41 100644 --- a/acs-visualiser/public/packet.js +++ b/acs-visualiser/public/packet.js @@ -13,10 +13,11 @@ function interp (from, to, by) { } export default class Packet { - constructor (vis, node, style) { + constructor (vis, node, style, stopping) { this.vis = vis; this.node = node; this.style = style; + this.stopping = stopping; } render (time, circle) { @@ -24,6 +25,8 @@ export default class Packet { let dT = (time - this.start) / 700; if (dT > 1) { + if (this.stopping) + return false; this.node = this.node.parent; if (!this.node.parent) return false; diff --git a/acs-visualiser/public/vis.js b/acs-visualiser/public/vis.js index e797c637..3e93986c 100644 --- a/acs-visualiser/public/vis.js +++ b/acs-visualiser/public/vis.js @@ -47,7 +47,7 @@ export default class Vis { if (graph.path) this.paths.set(graph.path, graph); - if (!nodes) { + if (!nodes || !nodes.length) { this.leaves.push(graph); graph.leaves = 1; graph.maxdepth = 0; @@ -101,7 +101,8 @@ export default class Vis { centre: o_cen, }; } - if (graph.too_many || !nodes) return; + if (graph.too_many || !nodes || nodes.length == 0) + return; for (const child of nodes) { this.pick_centres(child, angle, radius + ring, segment, ring); @@ -142,7 +143,7 @@ export default class Vis { } else { graph.text_roff = graph.radius; - const style = graph.online ? "circles" : "offline"; + const style = graph.is_cmd ? "CMD" : graph.online ? "circles" : "offline"; this.circle(pos[0], pos[1], graph.radius, style); } ctx.restore(); @@ -156,7 +157,10 @@ export default class Vis { console.log("No centre for %o", n); continue; } - ctx.strokeStyle = Style.circles + if (n.is_cmd) + ctx.strokeStyle = Style.CMD; + else + ctx.strokeStyle = Style.circles; ctx.beginPath(); ctx.moveTo(...graph.centre); ctx.lineTo(...n.centre); @@ -274,13 +278,13 @@ export default class Vis { this.pick_centres(this.graph, 0, 0, segment, ring); } - make_active (path, style) { + make_active (path, style, stopping) { let node = this.paths.get(path); if (node) { if (node.parent.too_many) { node = node.parent.overflow; } - this.active.add(new Packet(this, node, style)); + this.active.add(new Packet(this, node, style, stopping)); } }