I want to have a chart that tracks humidity - from a sensor emitting a value on MQTT on topic bathroom/humidity
and I want to show a threshold value on the same graph. On my NodeRed Dashboard2, I have a settings tab, where I can set a trigger threshold between 60% & 100% and I store that as a global.
This is a cutdown version of my flows, keeping it to the salient parts
[
{
"id": "d2613e8a7ebef70b",
"type": "group",
"z": "cce74ec2bc0d88e7",
"style": {
"stroke": "#999999",
"stroke-opacity": "1",
"fill": "none",
"fill-opacity": "1",
"label": true,
"label-position": "nw",
"color": "#a4a4a4"
},
"nodes": [
"fcc2df9b4baa6887",
"a4a5d58e92dd5bc5",
"e9981499e7f010c2",
"2b10105773804203",
"0014a87992537ef2"
],
"x": 394,
"y": 39,
"w": 652,
"h": 182
},
{
"id": "fcc2df9b4baa6887",
"type": "mqtt in",
"z": "cce74ec2bc0d88e7",
"g": "d2613e8a7ebef70b",
"name": "Humidity",
"topic": "bathroom/humidity",
"qos": "0",
"datatype": "json",
"broker": "3f447ded17b259ee",
"nl": false,
"rap": false,
"rh": 0,
"inputs": 0,
"x": 680,
"y": 180,
"wires": [
[
"a4a5d58e92dd5bc5",
"e9981499e7f010c2"
]
]
},
{
"id": "a4a5d58e92dd5bc5",
"type": "function",
"z": "cce74ec2bc0d88e7",
"g": "d2613e8a7ebef70b",
"name": "RecordHumidity",
"func": "flow.set('lastHumidity', msg.payload);\nreturn msg;\n",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 940,
"y": 140,
"wires": [
[]
]
},
{
"id": "e9981499e7f010c2",
"type": "ui-chart",
"z": "cce74ec2bc0d88e7",
"g": "d2613e8a7ebef70b",
"group": "fc3876ca5fad0f6a",
"name": "Humidity",
"label": "chart",
"order": 2,
"chartType": "line",
"category": "topic",
"categoryType": "msg",
"xAxisLabel": "Time",
"xAxisProperty": "",
"xAxisPropertyType": "timestamp",
"xAxisType": "time",
"xAxisFormat": "",
"xAxisFormatType": "auto",
"xmin": "",
"xmax": "",
"yAxisLabel": "Humidity %",
"yAxisProperty": "payload",
"yAxisPropertyType": "msg",
"ymin": "20",
"ymax": "100",
"bins": 10,
"action": "append",
"stackSeries": false,
"pointShape": "false",
"pointRadius": 4,
"showLegend": true,
"removeOlder": "4",
"removeOlderUnit": "3600",
"removeOlderPoints": "",
"colors": [
"#0095ff",
"#e01b24",
"#ff7f0e",
"#2ca02c",
"#a347e1",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"textColor": [
"#666666"
],
"textColorDefault": true,
"gridColor": [
"#e5e5e5"
],
"gridColorDefault": true,
"width": 6,
"height": 8,
"className": "",
"interpolation": "linear",
"x": 920,
"y": 180,
"wires": [
[]
]
},
{
"id": "2b10105773804203",
"type": "inject",
"z": "cce74ec2bc0d88e7",
"g": "d2613e8a7ebef70b",
"name": "OnStart",
"props": [
{
"p": "topic",
"vt": "str"
}
],
"repeat": "30",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"x": 500,
"y": 80,
"wires": [
[
"0014a87992537ef2"
]
]
},
{
"id": "0014a87992537ef2",
"type": "function",
"z": "cce74ec2bc0d88e7",
"g": "d2613e8a7ebef70b",
"name": "get humidityThreshold",
"func": "msg.payload = global.get('humidityThreshold');\nmsg.topic = 'bathroom/humidityThreshold'\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 700,
"y": 80,
"wires": [
[
"e9981499e7f010c2"
]
]
},
{
"id": "3f447ded17b259ee",
"type": "mqtt-broker",
"name": "Mosquitto",
"broker": "192.168.7.245",
"port": "1883",
"clientid": "",
"usetls": false,
"protocolVersion": "5",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"sessionExpiry": ""
},
{
"id": "fc3876ca5fad0f6a",
"type": "ui-group",
"name": "Humidity",
"page": "cda4aeea5584ffaa",
"width": 6,
"height": 1,
"order": 1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false",
"groupType": "default"
},
{
"id": "cda4aeea5584ffaa",
"type": "ui-page",
"name": "Bathroom",
"ui": "5158dba2ce9db01c",
"path": "/page1",
"icon": "home",
"layout": "grid",
"theme": "f149993e218cdb7d",
"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"
}
],
"order": 2,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "5158dba2ce9db01c",
"type": "ui-base",
"name": "Archery",
"path": "/dashboard",
"appIcon": "",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-control"
],
"showPathInSidebar": false,
"headerContent": "page",
"navigationStyle": "default",
"titleBarStyle": "default",
"showReconnectNotification": true,
"notificationDisplayTime": 1,
"showDisconnectNotification": true,
"allowInstall": true
},
{
"id": "f149993e218cdb7d",
"type": "ui-theme",
"name": "Default Theme",
"colors": {
"surface": "#ffffff",
"primary": "#0094CE",
"bgPage": "#eeeeee",
"groupBg": "#ffffff",
"groupOutline": "#cccccc"
},
"sizes": {
"density": "default",
"pagePadding": "12px",
"groupGap": "12px",
"groupBorderRadius": "4px",
"widgetGap": "12px"
}
},
{
"id": "4afc449ce3f4a5f7",
"type": "group",
"z": "cce74ec2bc0d88e7",
"style": {
"stroke": "#999999",
"stroke-opacity": "1",
"fill": "none",
"fill-opacity": "1",
"label": true,
"label-position": "nw",
"color": "#a4a4a4"
},
"nodes": [
"0d033b5b22ea8fe5",
"63069eb82a4078e0"
],
"x": 594,
"y": 279,
"w": 452,
"h": 82
},
{
"id": "0d033b5b22ea8fe5",
"type": "function",
"z": "cce74ec2bc0d88e7",
"g": "4afc449ce3f4a5f7",
"name": "StoreHumidityThreshold",
"func": "if (Number(msg.payload) <= 60) {\n msg.payload = '60';\n}\nif (Number(msg.payload) >= 100) {\n msg.payload = '100';\n}\nglobal.set ('humidityThreshold', Number(msg.payload));",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set ('humidityThreshold', 85);",
"finalize": "",
"libs": [],
"x": 910,
"y": 320,
"wires": [
[]
]
},
{
"id": "63069eb82a4078e0",
"type": "ui-slider",
"z": "cce74ec2bc0d88e7",
"g": "4afc449ce3f4a5f7",
"group": "b98e9fbe6d175507",
"name": "Threshold",
"label": "slider",
"tooltip": "",
"order": 1,
"width": 0,
"height": 0,
"passthru": false,
"outs": "all",
"topic": "topic",
"topicType": "msg",
"thumbLabel": "true",
"showTicks": "always",
"min": "60",
"max": "100",
"step": "5",
"className": "",
"iconPrepend": "",
"iconAppend": "",
"color": "",
"colorTrack": "",
"colorThumb": "",
"showTextField": false,
"x": 680,
"y": 320,
"wires": [
[
"0d033b5b22ea8fe5"
]
]
},
{
"id": "b98e9fbe6d175507",
"type": "ui-group",
"name": "Humidity",
"page": "0cafb08f3c034873",
"width": 6,
"height": 1,
"order": 5,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false",
"groupType": "default"
},
{
"id": "0cafb08f3c034873",
"type": "ui-page",
"name": "Bathroom settings",
"ui": "5158dba2ce9db01c",
"path": "/page2",
"icon": "home",
"layout": "grid",
"theme": "f149993e218cdb7d",
"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"
}
],
"order": 1,
"className": "",
"visible": true,
"disabled": false
},
{
"id": "e976caf56d5dbe5b",
"type": "global-config",
"env": [],
"modules": {
"@flowfuse/node-red-dashboard": "1.27.1"
}
}
]
Is this the way to do it, or are there more efficient ways?
I assume the 30s repeat inject will re-query the stored value and feed that in to the graph as another series (as I set msg.topic = bathrooom/humidityThreshold
, as well as passing msg.payload