2026-05-22 20:27:28 +02:00
[
{
"id" : "cse_tab" ,
"type" : "tab" ,
"label" : "CoreSync FROST + Influx + Grafana" ,
"disabled" : false ,
"info" : "Measurement and rotatingMachine telemetry are written as raw samples to local InfluxDB and as CoreSync-reduced knots to FROST and InfluxDB."
} ,
{
"id" : "cse_note" ,
"type" : "comment" ,
"z" : "cse_tab" ,
"name" : "Set FROST_USER and FROST_PASSWORD in the Node-RED environment before deploying." ,
"info" : "CoreSync emits FROST-ready HTTP requests. The HTTP request response is fed back with topic=frost.response so metadata lookup/create can continue." ,
"x" : 450 ,
"y" : 40 ,
"wires" : [ ]
} ,
{
"id" : "cse_ui_base" ,
"type" : "ui-base" ,
"name" : "EVOLV CoreSync" ,
"path" : "/dashboard" ,
"appIcon" : "" ,
"includeClientData" : true ,
"acceptsClientConfig" : [
"ui-notification" ,
"ui-control"
] ,
"showPathInSidebar" : false ,
"headerContent" : "page" ,
"navigationStyle" : "default" ,
"titleBarStyle" : "default"
} ,
{
"id" : "cse_ui_theme" ,
"type" : "ui-theme" ,
"name" : "CoreSync Theme" ,
"colors" : {
"surface" : "#ffffff" ,
"primary" : "#2364aa" ,
"bgPage" : "#f3f5f7" ,
"groupBg" : "#ffffff" ,
"groupOutline" : "#d5dce3"
} ,
"sizes" : {
"density" : "compact" ,
"pagePadding" : "12px" ,
"groupGap" : "12px" ,
"groupBorderRadius" : "6px" ,
"widgetGap" : "8px"
}
} ,
{
"id" : "cse_ui_page" ,
"type" : "ui-page" ,
"name" : "CoreSync FROST" ,
"ui" : "cse_ui_base" ,
"path" : "/coresync-frost" ,
"icon" : "timeline" ,
"layout" : "grid" ,
"theme" : "cse_ui_theme" ,
"breakpoints" : [
{
"name" : "Default" ,
"px" : "0" ,
"cols" : "12"
}
] ,
"order" : 1 ,
"className" : ""
} ,
{
"id" : "cse_ui_group_kpi" ,
"type" : "ui-group" ,
"name" : "Reduction Counters" ,
"page" : "cse_ui_page" ,
"width" : "12" ,
"height" : "1" ,
"order" : 1 ,
"showTitle" : true ,
"className" : ""
} ,
{
"id" : "cse_ui_group_chart" ,
"type" : "ui-group" ,
"name" : "Write Rates" ,
"page" : "cse_ui_page" ,
"width" : "12" ,
"height" : "1" ,
"order" : 2 ,
"showTitle" : true ,
"className" : ""
} ,
{
"id" : "cse_measure_flow" ,
"type" : "measurement" ,
"z" : "cse_tab" ,
"name" : "FROST Flow Sensor FT-101" ,
"scaling" : false ,
"i_min" : 0 ,
"i_max" : 120 ,
"i_offset" : 0 ,
"o_min" : 0 ,
"o_max" : 120 ,
"simulator" : false ,
"smooth_method" : "none" ,
"count" : 1 ,
"processOutputFormat" : "process" ,
"dbaseOutputFormat" : "frost" ,
"uuid" : "" ,
"assetTagCode" : "FT-101" ,
"tagCode" : "FT-101" ,
"supplier" : "demo" ,
"category" : "sensor" ,
"assetType" : "flow" ,
"model" : "demo-flow-transmitter" ,
"unit" : "m3/h" ,
"enableLog" : false ,
"logLevel" : "error" ,
"positionVsParent" : "upstream" ,
"positionIcon" : "" ,
"hasDistance" : false ,
"distance" : 0 ,
"distanceUnit" : "m" ,
"distanceDescription" : "" ,
"x" : 560 ,
"y" : 160 ,
"wires" : [
[
"cse_dbg_measure_process"
] ,
[
"cse_fn_measure_to_coresync" ,
"cse_fn_raw_influx"
] ,
[
"cse_rm_pump"
]
]
} ,
{
"id" : "cse_inj_measure_loop" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "1 Hz directional flow" ,
"props" : [
{
"p" : "payload"
}
] ,
"repeat" : "1" ,
"crontab" : "" ,
"once" : true ,
"onceDelay" : "1" ,
"topic" : "" ,
"payload" : "" ,
"payloadType" : "date" ,
"x" : 160 ,
"y" : 160 ,
"wires" : [
[
"cse_fn_measure_triangle"
]
]
} ,
{
"id" : "cse_fn_measure_triangle" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "triangle 0..100..0" ,
"func" : "let i = context.get('i') || 0;\nconst phase = i % 80;\nconst value = phase <= 40 ? phase * 2.5 : (80 - phase) * 2.5;\ncontext.set('i', i + 1);\nmsg.topic = 'measurement';\nmsg.payload = Math.round(value * 100) / 100;\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 360 ,
"y" : 160 ,
"wires" : [
[
"cse_measure_flow"
]
]
} ,
{
"id" : "cse_fn_measure_to_coresync" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "mAbs -> flow.measured.upstream.FT-101" ,
"func" : "const p = msg.payload;\nif (!p || !p.fields) return null;\nconst value = Number(p.fields.mAbs);\nif (!Number.isFinite(value)) return null;\nmsg.payload = {\n measurement: 'FT-101',\n fields: { 'flow.measured.upstream.FT-101': value },\n tags: { ...(p.tags || {}), tagcode: 'P-101', sensorTag: 'FT-101', unit: 'm3/h' },\n timestamp: p.timestamp || new Date().toISOString(),\n source: { ...(p.source || {}), softwareType: 'measurement', unit: 'm3/h' }\n};\nmsg.topic = msg.payload.measurement;\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 850 ,
"y" : 140 ,
"wires" : [
[
"cse_coresync"
]
]
} ,
{
"id" : "cse_rm_pump" ,
"type" : "rotatingMachine" ,
"z" : "cse_tab" ,
"name" : "FROST Pump P-101" ,
"speed" : "25" ,
"startup" : "1" ,
"warmup" : "1" ,
"shutdown" : "1" ,
"cooldown" : "1" ,
"movementMode" : "staticspeed" ,
"machineCurve" : "" ,
"processOutputFormat" : "process" ,
"dbaseOutputFormat" : "frost" ,
"uuid" : "" ,
"assetTagCode" : "P-101" ,
"assetTagNumber" : "P-101" ,
"supplier" : "" ,
"category" : "" ,
"assetType" : "" ,
"model" : "hidrostal-H05K-S03R" ,
"unit" : "m3/h" ,
"enableLog" : false ,
"logLevel" : "error" ,
"positionVsParent" : "atEquipment" ,
"positionIcon" : "" ,
"hasDistance" : false ,
"distance" : "" ,
"distanceUnit" : "m" ,
"distanceDescription" : "" ,
"x" : 560 ,
"y" : 360 ,
"wires" : [
[
"cse_dbg_rm_process"
] ,
[
"cse_coresync" ,
"cse_fn_raw_influx"
] ,
[
"cse_dbg_rm_parent"
]
]
} ,
{
"id" : "cse_inj_rm_mode" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "RM mode virtualControl" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"vt" : "str"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : true ,
"onceDelay" : "0.5" ,
"topic" : "setMode" ,
"payload" : "virtualControl" ,
"payloadType" : "str" ,
"x" : 180 ,
"y" : 280 ,
"wires" : [
[
"cse_rm_pump"
]
]
} ,
{
"id" : "cse_inj_rm_start" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "RM startup" ,
"props" : [
{
"p" : "payload" ,
"vt" : "str"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : true ,
"onceDelay" : "1.5" ,
"topic" : "" ,
"payload" : "startup" ,
"payloadType" : "str" ,
"x" : 150 ,
"y" : 320 ,
"wires" : [
[
"cse_fn_rm_sequence"
]
]
} ,
{
"id" : "cse_fn_rm_sequence" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "execSequence" ,
"func" : "msg.topic = 'execSequence';\nmsg.payload = { source: 'GUI', action: 'execSequence', parameter: msg.payload };\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 340 ,
"y" : 320 ,
"wires" : [
[
"cse_rm_pump"
]
]
} ,
{
"id" : "cse_inj_rm_setpoint" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "RM 5s setpoint wave" ,
"props" : [
{
"p" : "payload"
}
] ,
"repeat" : "5" ,
"crontab" : "" ,
"once" : true ,
"onceDelay" : "3" ,
"topic" : "" ,
"payload" : "" ,
"payloadType" : "date" ,
"x" : 170 ,
"y" : 380 ,
"wires" : [
[
"cse_fn_rm_setpoint"
]
]
} ,
{
"id" : "cse_fn_rm_setpoint" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "execMovement wave" ,
"func" : "let i = context.get('i') || 0;\nconst values = [25, 55, 85, 60, 35];\nconst setpoint = values[i % values.length];\ncontext.set('i', i + 1);\nmsg.topic = 'execMovement';\nmsg.payload = { source: 'GUI', action: 'execMovement', setpoint };\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 360 ,
"y" : 380 ,
"wires" : [
[
"cse_rm_pump"
]
]
} ,
{
"id" : "cse_inj_rm_pressure" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "RM pressure cycle" ,
"props" : [
{
"p" : "payload"
}
] ,
"repeat" : "2" ,
"crontab" : "" ,
"once" : true ,
"onceDelay" : "1" ,
"topic" : "" ,
"payload" : "" ,
"payloadType" : "date" ,
"x" : 160 ,
"y" : 440 ,
"wires" : [
[
"cse_fn_rm_pressure"
]
]
} ,
{
"id" : "cse_fn_rm_pressure" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "simulate upstream/downstream pressure" ,
"func" : "let i = context.get('i') || 0;\nconst up = 900 + ((i % 6) * 10);\nconst down = 1700 + ((i % 6) * 40);\ncontext.set('i', i + 1);\nreturn [\n { topic: 'simulateMeasurement', payload: { type: 'pressure', position: 'upstream', value: up, unit: 'mbar' } },\n { topic: 'simulateMeasurement', payload: { type: 'pressure', position: 'downstream', value: down, unit: 'mbar' } }\n];" ,
"outputs" : 2 ,
"noerr" : 0 ,
"x" : 390 ,
"y" : 440 ,
"wires" : [
[
"cse_rm_pump"
] ,
[
"cse_rm_pump"
]
]
} ,
{
"id" : "cse_coresync" ,
"type" : "coresync" ,
"z" : "cse_tab" ,
"name" : "CoreSync to WBD FROST" ,
"frostBaseUrl" : "https://sta.wbd-rd.nl/FROST-Server/" ,
"serviceVersion" : "v1.1" ,
"dbaseFormat" : "frost" ,
"assetTagOverride" : "" ,
"sensorTagOverride" : "" ,
"comparisonMode" : "angle" ,
"angleToleranceDeg" : 1 ,
"timeScaleMs" : 1000 ,
"maxGapMs" : 30000 ,
"minDeltaTimeMs" : 0 ,
"minDeltaValue" : 0 ,
"burstWindowMs" : 10 ,
"maxQueuedObservationsPerStream" : 2 ,
"diagnosticsEnabled" : false ,
"x" : 1120 ,
"y" : 260 ,
"wires" : [
[
"cse_dbg_coresync_process"
] ,
[
"cse_fn_frost_auth" ,
"cse_fn_knot_influx"
] ,
[
"cse_dbg_coresync_parent"
]
]
} ,
{
"id" : "cse_inj_flush" ,
"type" : "inject" ,
"z" : "cse_tab" ,
"name" : "CoreSync flush 15s" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
}
] ,
"repeat" : "15" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "coresync.flush" ,
"x" : 860 ,
"y" : 300 ,
"wires" : [
[
"cse_coresync"
]
]
} ,
{
"id" : "cse_fn_frost_auth" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "FROST basic auth from env" ,
"func" : "const user = env.get('FROST_USER');\nconst password = env.get('FROST_PASSWORD');\nif (!user || !password) {\n node.status({ fill: 'red', shape: 'ring', text: 'missing FROST_USER/FROST_PASSWORD' });\n return null;\n}\nmsg.headers = { ...(msg.headers || {}), Authorization: 'Basic ' + Buffer.from(`${user}:${password}`).toString('base64') };\nnode.status({ fill: 'green', shape: 'dot', text: msg.topic });\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 1420 ,
"y" : 220 ,
"wires" : [
[
"cse_http_frost"
]
]
} ,
{
"id" : "cse_http_frost" ,
"type" : "http request" ,
"z" : "cse_tab" ,
"name" : "Send to FROST" ,
"method" : "use" ,
"ret" : "txt" ,
"paytoqs" : false ,
"url" : "" ,
"persist" : false ,
"authType" : "" ,
"senderr" : false ,
"x" : 1630 ,
"y" : 220 ,
"wires" : [
[
"cse_fn_frost_response"
]
]
} ,
{
"id" : "cse_fn_frost_response" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "topic=frost.response" ,
"func" : "if (typeof msg.payload === 'string') {\n try { msg.payload = JSON.parse(msg.payload); } catch (_) { /* keep raw */ }\n}\nconst metric = (msg._coreSync?.kind === 'observation' && msg.statusCode && msg.statusCode < 400)\n ? { topic: 'frostObservation', payload: 1 }\n : null;\nmsg.topic = 'frost.response';\nreturn [msg, metric];" ,
"outputs" : 2 ,
"noerr" : 0 ,
"x" : 1840 ,
"y" : 220 ,
"wires" : [
[
"cse_coresync" ,
"cse_dbg_frost_response"
] ,
[
"cse_fn_reduction_metrics"
]
]
} ,
{
"id" : "cse_fn_raw_influx" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "raw EVOLV -> Influx line protocol" ,
"func" : "const p = msg.payload;\nif (!p || !p.measurement || !p.fields) return null;\nconst esc = (s) => String(s).replace(/,/g, '\\\\,').replace(/ /g, '\\\\ ').replace(/=/g, '\\\\=');\nconst escString = (s) => String(s).replace(/\"/g, '\\\\\"');\nconst tags = Object.entries(p.tags || {})\n .filter(([, v]) => v !== undefined && v !== null && v !== '')\n .map(([k, v]) => `${esc(k)}=${esc(v)}`)\n .join(',');\nconst fields = Object.entries(p.fields)\n .filter(([, v]) => v !== undefined && v !== null)\n .map(([k, v]) => {\n const n = Number(v);\n if (typeof v === 'number' && Number.isFinite(v)) return `${esc(k)}=${v}`;\n if (typeof v === 'boolean') return `${esc(k)}=${v}`;\n if (Number.isFinite(n) && String(v).trim() !== '') return `${esc(k)}=${n}`;\n return `${esc(k)}=\"${escString(v)}\"`;\n });\nif (!fields.length) return null;\nconst t = Date.parse(p.timestamp);\nconst ns = `${Number.isFinite(t) ? t : Date.now()}000000`;\nmsg._coreSyncDemo = { rawFields: fields.length };\nmsg.payload = `${esc(p.measurement)}${tags ? ',' + tags : ''} ${fields.join(',')} ${ns}`;\nmsg.headers = { Authorization: 'Token evolv-dev-token', 'Content-Type': 'text/plain' };\nmsg.url = 'http://influxdb:8086/api/v2/write?org=evolv&bucket=telemetry&precision=ns';\nmsg.method = 'POST';\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 880 ,
"y" : 560 ,
"wires" : [
[
"cse_http_influx_raw"
]
]
} ,
{
"id" : "cse_http_influx_raw" ,
"type" : "http request" ,
"z" : "cse_tab" ,
"name" : "Write raw InfluxDB" ,
"method" : "use" ,
"ret" : "txt" ,
"paytoqs" : false ,
"url" : "" ,
"persist" : false ,
"authType" : "" ,
"senderr" : false ,
"x" : 1140 ,
"y" : 560 ,
"wires" : [
[
"cse_fn_influx_raw_status"
]
]
} ,
{
"id" : "cse_fn_knot_influx" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "CoreSync knot -> Influx line protocol" ,
"func" : "if (msg.topic !== 'frost.observation.create' || !msg.payload) return null;\nconst obs = msg.payload;\nconst params = obs.parameters || {};\nconst streamKey = params.evolvStreamKey || msg._coreSync?.streamKey || 'unknown';\nconst parts = streamKey.split(':');\nconst esc = (s) => String(s).replace(/,/g, '\\\\,').replace(/ /g, '\\\\ ').replace(/=/g, '\\\\=');\nconst tags = {\n streamKey,\n thing: parts[0] || 'unknown',\n type: parts[1] || 'unknown',\n variant: parts[2] || 'unknown',\n position: parts[3] || 'unknown',\n sensorTag: parts[4] || 'unknown',\n reason: params.reductionReason || 'unknown',\n direction: params.direction || 'unknown'\n};\nconst tagText = Object.entries(tags).map(([k, v]) => `${esc(k)}=${esc(v)}`).join(',');\nconst fields = [`result=${Number(obs.result)}`, 'knot=1i'];\nif (Number.isFinite(Number(params.slope))) fields.push(`slope=${Number(params.slope)}`);\nif (Number.isFinite(Number(params.previousValue))) fields.push(`previousValue=${Number(params.previousValue)}`);\nconst t = Date.parse(obs.phenomenonTime);\nconst ns = `${Number.isFinite(t) ? t : Date.now()}000000`;\nmsg._coreSyncDemo = { knotFields: 1 };\nmsg.payload = `coresync_knots,${tagText} ${fields.join(',')} ${ns}`;\nmsg.headers = { Authorization: 'Token evolv-dev-token', 'Content-Type': 'text/plain' };\nmsg.url = 'http://influxdb:8086/api/v2/write?org=evolv&bucket=telemetry&precision=ns';\nmsg.method = 'POST';\nreturn msg;" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 1430 ,
"y" : 300 ,
"wires" : [
[
"cse_http_influx_knot"
]
]
} ,
{
"id" : "cse_http_influx_knot" ,
"type" : "http request" ,
"z" : "cse_tab" ,
"name" : "Write knot InfluxDB" ,
"method" : "use" ,
"ret" : "txt" ,
"paytoqs" : false ,
"url" : "" ,
"persist" : false ,
"authType" : "" ,
"senderr" : false ,
"x" : 1680 ,
"y" : 300 ,
"wires" : [
[
"cse_fn_influx_knot_status"
]
]
} ,
{
"id" : "cse_fn_influx_raw_status" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "raw write status" ,
"func" : "const count = (context.get('count') || 0) + 1;\nconst errors = context.get('errors') || 0;\nif (msg.statusCode && msg.statusCode >= 400) {\n context.set('errors', errors + 1);\n node.status({ fill: 'red', shape: 'ring', text: `raw ERR ${errors + 1}/${count}` });\n context.set('count', count);\n return null;\n}\nnode.status({ fill: 'green', shape: 'dot', text: `raw ${count} writes` });\ncontext.set('count', count);\nreturn { topic: 'rawFields', payload: msg._coreSyncDemo?.rawFields || 1 };" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 1360 ,
"y" : 560 ,
"wires" : [
[
"cse_fn_reduction_metrics"
]
]
} ,
{
"id" : "cse_fn_influx_knot_status" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "knot write status" ,
"func" : "const count = (context.get('count') || 0) + 1;\nconst errors = context.get('errors') || 0;\nif (msg.statusCode && msg.statusCode >= 400) {\n context.set('errors', errors + 1);\n node.status({ fill: 'red', shape: 'ring', text: `knot ERR ${errors + 1}/${count}` });\n context.set('count', count);\n return null;\n}\nnode.status({ fill: 'green', shape: 'dot', text: `knot ${count} writes` });\ncontext.set('count', count);\nreturn { topic: 'knotFields', payload: msg._coreSyncDemo?.knotFields || 1 };" ,
"outputs" : 1 ,
"noerr" : 0 ,
"x" : 1900 ,
"y" : 300 ,
"wires" : [
[
"cse_fn_reduction_metrics"
]
]
} ,
{
"id" : "cse_fn_reduction_metrics" ,
"type" : "function" ,
"z" : "cse_tab" ,
"name" : "Live reduction metrics" ,
"func" : "const stats = context.get('stats') || { rawFields: 0, knotFields: 0, frostObservations: 0, started: Date.now() };\nconst n = Number(msg.payload) || 0;\nif (msg.topic === 'rawFields') stats.rawFields += n;\nif (msg.topic === 'knotFields') stats.knotFields += n;\nif (msg.topic === 'frostObservation') stats.frostObservations += n;\ncontext.set('stats', stats);\n\nconst saved = stats.rawFields > 0 ? Math.max(0, 100 * (1 - (stats.knotFields / stats.rawFields))) : 0;\nconst elapsedSec = Math.max(1, (Date.now() - stats.started) / 1000);\nconst rawRate = stats.rawFields / elapsedSec;\nconst knotRate = stats.knotFields / elapsedSec;\n\nnode.status({ fill: 'green', shape: 'dot', text: `${stats.rawFields} raw -> ${stats.knotFields} knots (${saved.toFixed(1)}% saved)` });\n\nreturn [\n { payload: `Raw fields: ${stats.rawFields} | CoreSync knots: ${stats.knotFields} | FROST observations: ${stats.frostObservations} | Saved: ${saved.toFixed(1)}%` },\n { payload: Number(saved.toFixed(1)) },\n { topic: 'raw fields/s', payload: Number(rawRate.toFixed(3)), timestamp: Date.now() },\n { topic: 'knot fields/s', payload: Number(knotRate.toFixed(3)), timestamp: Date.now() },\n { payload: stats.frostObservations }\n];" ,
"outputs" : 5 ,
"noerr" : 0 ,
"x" : 1620 ,
"y" : 500 ,
"wires" : [
[
"cse_ui_text_summary"
] ,
[
"cse_ui_gauge_saved"
] ,
[
"cse_ui_chart_raw"
] ,
[
"cse_ui_chart_knot"
] ,
[
"cse_ui_text_frost"
]
]
} ,
{
"id" : "cse_ui_text_summary" ,
"type" : "ui-text" ,
"z" : "cse_tab" ,
"group" : "cse_ui_group_kpi" ,
"name" : "Reduction summary" ,
"label" : "Reduction" ,
"order" : 1 ,
"width" : "8" ,
"height" : "1" ,
"format" : "{{msg.payload}}" ,
"layout" : "row-spread" ,
"style" : false ,
"font" : "" ,
"fontSize" : "" ,
"color" : "" ,
"x" : 1890 ,
"y" : 460 ,
"wires" : [ ]
} ,
{
"id" : "cse_ui_text_frost" ,
"type" : "ui-text" ,
"z" : "cse_tab" ,
"group" : "cse_ui_group_kpi" ,
"name" : "FROST observations" ,
"label" : "FROST observations" ,
"order" : 2 ,
"width" : "4" ,
"height" : "1" ,
"format" : "{{msg.payload}}" ,
"layout" : "row-spread" ,
"style" : false ,
"font" : "" ,
"fontSize" : "" ,
"color" : "" ,
"x" : 1900 ,
"y" : 620 ,
"wires" : [ ]
} ,
{
"id" : "cse_ui_gauge_saved" ,
"type" : "ui-gauge" ,
"z" : "cse_tab" ,
"group" : "cse_ui_group_kpi" ,
"name" : "Saved gauge" ,
"gtype" : "gauge-half" ,
"gstyle" : "Rounded" ,
"title" : "Data Saved" ,
"units" : "%" ,
"prefix" : "" ,
"suffix" : "%" ,
"min" : 0 ,
"max" : 100 ,
"segments" : [
{
"color" : "#d64545" ,
"from" : 0
} ,
{
"color" : "#e8a23a" ,
"from" : 40
} ,
{
"color" : "#2f9e44" ,
"from" : 70
}
] ,
"width" : "4" ,
"height" : "3" ,
"order" : 3 ,
"x" : 1880 ,
"y" : 500 ,
"wires" : [ ]
} ,
{
"id" : "cse_ui_chart_raw" ,
"type" : "ui-chart" ,
"z" : "cse_tab" ,
"group" : "cse_ui_group_chart" ,
"name" : "Raw write rate" ,
"label" : "Raw field write rate" ,
"order" : 1 ,
2026-05-29 19:18:45 +02:00
"width" : 6 ,
"height" : 4 ,
2026-05-22 20:27:28 +02:00
"chartType" : "line" ,
"category" : "topic" ,
"xAxisLabel" : "time" ,
"xAxisType" : "time" ,
"yAxisLabel" : "fields/s" ,
"removeOlder" : "15" ,
"removeOlderUnit" : "60" ,
"x" : 1890 ,
"y" : 540 ,
"wires" : [ ] ,
"showLegend" : false ,
"categoryType" : "msg" ,
"xAxisProperty" : "" ,
"xAxisPropertyType" : "timestamp" ,
"yAxisProperty" : "payload" ,
"yAxisPropertyType" : "msg" ,
"action" : "append" ,
2026-05-29 19:18:45 +02:00
"interpolation" : "linear" ,
"colors" : [
"#0095FF" ,
"#FF0000" ,
"#FF7F0E" ,
"#2CA02C" ,
"#A347E1" ,
"#D62728" ,
"#FF9896" ,
"#9467BD" ,
"#C5B0D5"
]
2026-05-22 20:27:28 +02:00
} ,
{
"id" : "cse_ui_chart_knot" ,
"type" : "ui-chart" ,
"z" : "cse_tab" ,
"group" : "cse_ui_group_chart" ,
"name" : "Knot write rate" ,
"label" : "CoreSync knot write rate" ,
"order" : 2 ,
2026-05-29 19:18:45 +02:00
"width" : 6 ,
"height" : 4 ,
2026-05-22 20:27:28 +02:00
"chartType" : "line" ,
"category" : "topic" ,
"xAxisLabel" : "time" ,
"xAxisType" : "time" ,
"yAxisLabel" : "knots/s" ,
"removeOlder" : "15" ,
"removeOlderUnit" : "60" ,
"x" : 1890 ,
"y" : 580 ,
"wires" : [ ] ,
"showLegend" : false ,
"categoryType" : "msg" ,
"xAxisProperty" : "" ,
"xAxisPropertyType" : "timestamp" ,
"yAxisProperty" : "payload" ,
"yAxisPropertyType" : "msg" ,
"action" : "append" ,
2026-05-29 19:18:45 +02:00
"interpolation" : "linear" ,
"colors" : [
"#0095FF" ,
"#FF0000" ,
"#FF7F0E" ,
"#2CA02C" ,
"#A347E1" ,
"#D62728" ,
"#FF9896" ,
"#9467BD" ,
"#C5B0D5"
]
2026-05-22 20:27:28 +02:00
} ,
{
"id" : "cse_dbg_measure_process" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "measurement process" ,
"active" : false ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 850 ,
"y" : 100 ,
"wires" : [ ]
} ,
{
"id" : "cse_dbg_rm_process" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "rotatingMachine process" ,
"active" : false ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 840 ,
"y" : 360 ,
"wires" : [ ]
} ,
{
"id" : "cse_dbg_rm_parent" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "rotatingMachine parent" ,
"active" : false ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 840 ,
"y" : 400 ,
"wires" : [ ]
} ,
{
"id" : "cse_dbg_coresync_process" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "CoreSync diagnostics" ,
"active" : true ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 1410 ,
"y" : 180 ,
"wires" : [ ]
} ,
{
"id" : "cse_dbg_coresync_parent" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "CoreSync parent" ,
"active" : false ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 1400 ,
"y" : 340 ,
"wires" : [ ]
} ,
{
"id" : "cse_dbg_frost_response" ,
"type" : "debug" ,
"z" : "cse_tab" ,
"name" : "FROST response" ,
"active" : false ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "statusCode" ,
"targetType" : "msg" ,
"x" : 2070 ,
"y" : 220 ,
"wires" : [ ]
}
]