added functioning master control and vu meter ui
This commit is contained in:
402
flows/master_vu_dashboard.json
Normal file
402
flows/master_vu_dashboard.json
Normal file
@@ -0,0 +1,402 @@
|
||||
[
|
||||
{
|
||||
"id": "tabXilicaDash",
|
||||
"type": "tab",
|
||||
"label": "Xilica FR1 Dashboard",
|
||||
"disabled": false,
|
||||
"info": ""
|
||||
},
|
||||
{
|
||||
"id": "8ec2e59f8a7e993a",
|
||||
"type": "ui-text",
|
||||
"z": "tabXilicaDash",
|
||||
"group": "ui_group_master",
|
||||
"order": "",
|
||||
"width": "",
|
||||
"height": "",
|
||||
"name": "Current (dB)",
|
||||
"label": "Current (dB)",
|
||||
"layout": "row-spread",
|
||||
"style": false,
|
||||
"font": "",
|
||||
"fontSize": "",
|
||||
"color": "#000000",
|
||||
"wrapText": false,
|
||||
"className": "",
|
||||
"value": "payload",
|
||||
"valueType": "msg",
|
||||
"x": 1090,
|
||||
"y": 400,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "f64df68a17fafed8",
|
||||
"type": "ui-slider",
|
||||
"z": "tabXilicaDash",
|
||||
"group": "ui_group_master",
|
||||
"name": "MASTER_GAIN (dB)",
|
||||
"label": "MASTER_GAIN (dB)",
|
||||
"order": "",
|
||||
"width": "1",
|
||||
"height": "7",
|
||||
"passthru": false,
|
||||
"outs": "all",
|
||||
"topic": "",
|
||||
"topicType": "str",
|
||||
"thumbLabel": "true",
|
||||
"showTicks": "false",
|
||||
"min": -100,
|
||||
"max": -18,
|
||||
"step": 0.5,
|
||||
"className": "",
|
||||
"iconPrepend": "",
|
||||
"iconAppend": "",
|
||||
"color": "grey",
|
||||
"colorTrack": "blue",
|
||||
"colorThumb": "black",
|
||||
"showTextField": false,
|
||||
"x": 540,
|
||||
"y": 240,
|
||||
"wires": [
|
||||
[
|
||||
"ebeeed016133d1b1"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ebeeed016133d1b1",
|
||||
"type": "function",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "build SET MASTER_GAIN <v>",
|
||||
"func": "const v = Number(msg.payload);\n// show value on the slider label while sending\nnode.status({text: v.toFixed(1)+\" dB\"});\nmsg.payload = `SET MASTER_GAIN ${v}`;\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"timeout": "",
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 850,
|
||||
"y": 240,
|
||||
"wires": [
|
||||
[
|
||||
"37a2739c39fb28c6"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ff5d04b8e8358ac7",
|
||||
"type": "inject",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "poll GET",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
}
|
||||
],
|
||||
"repeat": "0.1",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "0.5",
|
||||
"topic": "",
|
||||
"payload": "GET MASTER_GAIN",
|
||||
"payloadType": "str",
|
||||
"x": 480,
|
||||
"y": 320,
|
||||
"wires": [
|
||||
[
|
||||
"37a2739c39fb28c6"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "37a2739c39fb28c6",
|
||||
"type": "function",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "append \\r",
|
||||
"func": "if (typeof msg.payload !== 'string') msg.payload = String(msg.payload);\nmsg.payload += \"\\r\";\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"x": 740,
|
||||
"y": 340,
|
||||
"wires": [
|
||||
[
|
||||
"6f693811595db658"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6f693811595db658",
|
||||
"type": "tcp request",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "FR1 192.168.1.244:10007",
|
||||
"server": "192.168.1.244",
|
||||
"port": "10007",
|
||||
"out": "sit",
|
||||
"ret": "string",
|
||||
"splitc": " ",
|
||||
"newline": "",
|
||||
"trim": false,
|
||||
"tls": "",
|
||||
"x": 550,
|
||||
"y": 400,
|
||||
"wires": [
|
||||
[
|
||||
"fd2ea6ae724caf88",
|
||||
"2f4b662b4ed88da3",
|
||||
"8d72b821fca250d0"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2f4b662b4ed88da3",
|
||||
"type": "function",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "parse GET reply → number",
|
||||
"func": "// Expected: MASTER_GAIN=-6.0\\r or OK\\r after SET\nconst s = (msg.payload||\"\").trim();\nif (/^MASTER_GAIN\\s*=/.test(s)) {\n const m = s.match(/=\\s*([-+]?\\d+(?:\\.\\d+)?)/);\n if (m) {\n const val = Number(m[1]);\n // update text and slider\n node.send([{payload: val.toFixed(1)}, {payload: val}]);\n }\n}\nreturn null; // outputs handled via node.send",
|
||||
"outputs": 2,
|
||||
"x": 820,
|
||||
"y": 400,
|
||||
"wires": [
|
||||
[
|
||||
"8ec2e59f8a7e993a"
|
||||
],
|
||||
[
|
||||
"8746aa1d3cf6fc69"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "fd2ea6ae724caf88",
|
||||
"type": "debug",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "Raw replies",
|
||||
"active": false,
|
||||
"tosidebar": true,
|
||||
"complete": "payload",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 850,
|
||||
"y": 500,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "8746aa1d3cf6fc69",
|
||||
"type": "link out",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "link out 2",
|
||||
"mode": "link",
|
||||
"links": [
|
||||
"f267313c2d612dea"
|
||||
],
|
||||
"x": 985,
|
||||
"y": 440,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "f267313c2d612dea",
|
||||
"type": "link in",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "link in 2",
|
||||
"links": [
|
||||
"8746aa1d3cf6fc69"
|
||||
],
|
||||
"x": 265,
|
||||
"y": 240,
|
||||
"wires": [
|
||||
[
|
||||
"f64df68a17fafed8"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c2fce4e36d067d34",
|
||||
"type": "inject",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "poll VU_MASTER",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
}
|
||||
],
|
||||
"repeat": "0.2",
|
||||
"crontab": "",
|
||||
"once": true,
|
||||
"onceDelay": "0.5",
|
||||
"topic": "",
|
||||
"payload": "GET VU_MASTER",
|
||||
"payloadType": "str",
|
||||
"x": 150,
|
||||
"y": 400,
|
||||
"wires": [
|
||||
[
|
||||
"2100bc16276dbd8d"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8d72b821fca250d0",
|
||||
"type": "function",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "parse VU_MASTER replies",
|
||||
"func": "const s = String(msg.payload || '').trim();\nconst m = s.match(/^VU[_\\s]?MASTER\\s*=\\s*([-+]?\\d+(?:\\.\\d+)?)/i);\nif (!m) return null;\nmsg.payload = Number(m[1]); // e.g. -28.7\nreturn msg;\n",
|
||||
"outputs": 1,
|
||||
"timeout": "",
|
||||
"noerr": 0,
|
||||
"initialize": "",
|
||||
"finalize": "",
|
||||
"libs": [],
|
||||
"x": 600,
|
||||
"y": 840,
|
||||
"wires": [
|
||||
[
|
||||
"a3665ff2cf1a93da"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2100bc16276dbd8d",
|
||||
"type": "function",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "append \\r",
|
||||
"func": "if (typeof msg.payload !== 'string') msg.payload = String(msg.payload);\nmsg.payload += \"\\r\";\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"x": 320,
|
||||
"y": 400,
|
||||
"wires": [
|
||||
[
|
||||
"6f693811595db658"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "3d0401ed2bb481cd",
|
||||
"type": "debug",
|
||||
"z": "tabXilicaDash",
|
||||
"name": "Template OUT",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"complete": "payload",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 1100,
|
||||
"y": 840,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "a3665ff2cf1a93da",
|
||||
"type": "ui-template",
|
||||
"z": "tabXilicaDash",
|
||||
"group": "ui_group_meters",
|
||||
"page": "",
|
||||
"ui": "",
|
||||
"name": "vu_master",
|
||||
"order": 0,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"head": "",
|
||||
"format": "<template>\n <div class=\"vu2\">\n <div class=\"vu2-hdr\">\n <strong>VU_MASTER</strong>\n <span class=\"vu2-readout\">{{ level.toFixed(1) }} dB</span>\n </div>\n\n <div class=\"vu2-bar\">\n <div class=\"vu2-fill\" :style=\"{ width: percent + '%' }\"></div>\n <div class=\"vu2-peak\" :style=\"{ left: peakPercent + '%' }\"></div>\n <span class=\"vu2-tick\" v-for=\"t in ticks\" :key=\"t\" :style=\"{ left: t + '%' }\"></span>\n </div>\n\n <div class=\"vu2-ftr\">\n <span>{{ min }} dB</span>\n <span>−12</span>\n <span>−3</span>\n <span>{{ max }} dB</span>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n // IMPORTANT for Dashboard 2: msg must be a prop to be reactive\n props: ['msg'],\n\n data: () => ({\n min: -60,\n max: 0,\n level: -60,\n peak: -60,\n decayDbPerSec: 6, // peak falls this many dB per second\n _timer: null,\n ticks: [0, 80, 95, 100] // % marks along the bar\n }),\n\n computed: {\n percent () {\n const v = Math.min(this.max, Math.max(this.min, this.level));\n return ((v - this.min) / (this.max - this.min)) * 100;\n },\n peakPercent () {\n const v = Math.min(this.max, Math.max(this.min, this.peak));\n return ((v - this.min) / (this.max - this.min)) * 100;\n }\n },\n\n watch: {\n // react to any incoming message\n msg: {\n deep: true,\n immediate: true,\n handler (m) {\n if (!m) return;\n\n if (m.min !== undefined && Number.isFinite(+m.min)) this.min = +m.min;\n if (m.max !== undefined && Number.isFinite(+m.max)) this.max = +m.max;\n\n if (m.payload !== undefined) {\n const n = Number(m.payload);\n if (Number.isFinite(n)) {\n this.level = n;\n if (n > this.peak) this.peak = n; // update peak on rise\n }\n }\n }\n }\n },\n\n mounted () {\n // peak decay loop\n const dt = 100; // ms\n this._timer = setInterval(() => {\n const step = this.decayDbPerSec * (dt / 1000);\n if (this.peak > this.level) this.peak = Math.max(this.level, this.peak - step);\n else this.peak = this.level;\n }, dt);\n },\n\n unmounted () {\n if (this._timer) clearInterval(this._timer);\n }\n}\n</script>\n\n<style>\n.vu2 { width:100%; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif; }\n.vu2-hdr, .vu2-ftr {\n display:flex; justify-content:space-between; align-items:center;\n}\n.vu2-readout { font-variant-numeric: tabular-nums; opacity:.8; }\n\n.vu2-bar {\n position:relative; width:100%; height:18px; margin:6px 0 4px; border-radius:4px;\n background:#0b0f14; overflow:hidden; box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);\n}\n.vu2-fill {\n position:absolute; top:0; bottom:0; left:0; z-index:1; transition:width 90ms linear;\n background:linear-gradient(90deg,\n #10b981 0%, #10b981 80%, /* green up to -12 dB */\n #f59e0b 80%, #f59e0b 95%, /* amber to -3 dB */\n #ef4444 95%, #ef4444 100%); /* red above -3 dB */\n}\n.vu2-peak {\n position:absolute; top:0; bottom:0; width:2px; background:rgba(255,255,255,.9);\n box-shadow:0 0 4px rgba(255,255,255,.9); z-index:2;\n}\n.vu2-tick {\n position:absolute; top:0; bottom:0; width:1px; background:rgba(255,255,255,.15); z-index:0;\n}\n.vu2-ftr span { font-size:12px; color:rgba(255,255,255,.6); }\n</style>\n",
|
||||
"storeOutMessages": true,
|
||||
"passthru": true,
|
||||
"resendOnRefresh": true,
|
||||
"templateScope": "local",
|
||||
"className": "",
|
||||
"x": 870,
|
||||
"y": 840,
|
||||
"wires": [
|
||||
[
|
||||
"3d0401ed2bb481cd"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ui_group_master",
|
||||
"type": "ui-group",
|
||||
"name": "Master Gain",
|
||||
"page": "ui_page_solaro",
|
||||
"width": "2",
|
||||
"height": "8",
|
||||
"showTitle": true,
|
||||
"className": "",
|
||||
"visible": "true",
|
||||
"disabled": "false",
|
||||
"groupType": "default"
|
||||
},
|
||||
{
|
||||
"id": "ui_group_meters",
|
||||
"type": "ui-group",
|
||||
"name": "Meters",
|
||||
"page": "ui_page_solaro",
|
||||
"width": "6",
|
||||
"height": "6",
|
||||
"showTitle": true,
|
||||
"className": "",
|
||||
"visible": "true",
|
||||
"disabled": "false",
|
||||
"groupType": "default"
|
||||
},
|
||||
{
|
||||
"id": "ui_page_solaro",
|
||||
"type": "ui-page",
|
||||
"name": "Solaro FR1",
|
||||
"ui": "ui_base_main",
|
||||
"path": "",
|
||||
"icon": "volume-high",
|
||||
"layout": "grid",
|
||||
"theme": "efd7cd1777464c3d",
|
||||
"breakpoints": [
|
||||
{
|
||||
"name": "Default",
|
||||
"px": "0",
|
||||
"cols": "3"
|
||||
},
|
||||
{
|
||||
"name": "Tablet",
|
||||
"px": "576",
|
||||
"cols": "6"
|
||||
},
|
||||
{
|
||||
"name": "Small Desktop",
|
||||
"px": "768",
|
||||
"cols": "9"
|
||||
},
|
||||
{
|
||||
"name": "Desktop",
|
||||
"px": "1024",
|
||||
"cols": "12"
|
||||
}
|
||||
],
|
||||
"className": "",
|
||||
"visible": "true",
|
||||
"disabled": "false"
|
||||
},
|
||||
{
|
||||
"id": "ui_base_main",
|
||||
"type": "ui-base",
|
||||
"name": "Main UI",
|
||||
"path": "/ui",
|
||||
"headerContent": "page",
|
||||
"titleBarStyle": "default",
|
||||
"showReconnectNotification": true,
|
||||
"notificationDisplayTime": 5,
|
||||
"showDisconnectNotification": true,
|
||||
"allowInstall": true
|
||||
},
|
||||
{
|
||||
"id": "efd7cd1777464c3d",
|
||||
"type": "ui-theme",
|
||||
"name": "Theme Name",
|
||||
"colors": {
|
||||
"surface": "#ffffff",
|
||||
"primary": "#0094ce",
|
||||
"bgPage": "#eeeeee",
|
||||
"groupBg": "#ffffff",
|
||||
"groupOutline": "#cccccc"
|
||||
},
|
||||
"sizes": {
|
||||
"density": "default",
|
||||
"pagePadding": "12px",
|
||||
"groupGap": "12px",
|
||||
"groupBorderRadius": "4px",
|
||||
"widgetGap": "12px"
|
||||
}
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user