I'm working on a fermentation management system for controlling tank temperatures during fermentation in a commercial winery on 17 different tanks. This is using some temperature probes from IOT4.eu and some solenoid valves hooked up to DLI power strips with all communication going through MQTT. This is my first NR project and all of my programming experience is from quite a while ago. This is my example control for one tank and I have 17 tanks total to control. Ideally, this will all be working with a dashboard to graph all of the tanks that are currently "on", controlling temperature and flexibility to control the upper and lower setpoints for the temperature range. I'm interested in any efficiencies in the design that I'm not seeing and I have a few questions below.
Thoughts on how best to turn off controls for specific tanks when temperature control isn't wanted on those tanks? I'd like to tie this into the dashboard as well and have an on-off switch for each tank with the setpoints for each tank.
What's the best option for doing a graph with data from Influxdb? Keeping everything in NR would be ideal but Grafana seems to have some really good options for this but then I would have to have setpoint controls in a different interface from the graph.
It took a little while to work through the logic of controlling the power strip but I think this is pretty good - NR continuously feeds the power strip with what it wants to do, just to make sure that the valve is in the correct state at all times instead of relying on a single command. The command is the same until the temperature determines that it should be different. The power strip will return to its prior state in the event of a power failure as well.
[
{
"id": "f6200681b265563b",
"type": "tab",
"label": "Prod",
"disabled": false,
"info": "",
"env": []
},
{
"id": "a95558832e711631",
"type": "debug",
"z": "f6200681b265563b",
"name": "TankT1-On",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "payload",
"statusType": "auto",
"x": 610,
"y": 40,
"wires": []
},
{
"id": "7c8d261e5f6d0998",
"type": "mqtt out",
"z": "f6200681b265563b",
"name": "",
"topic": "Power1/outlet/1/set",
"qos": "2",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "8aa408ca715b9482",
"x": 720,
"y": 100,
"wires": []
},
{
"id": "79ef3fe1a242a713",
"type": "debug",
"z": "f6200681b265563b",
"name": "TankT1-Off",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "payload",
"statusType": "auto",
"x": 610,
"y": 160,
"wires": []
},
{
"id": "bd1daf1565ee885c",
"type": "change",
"z": "f6200681b265563b",
"name": "Upper",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "1",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 510,
"y": 80,
"wires": [
[
"7c8d261e5f6d0998"
]
]
},
{
"id": "897ba8f3f231a1f0",
"type": "change",
"z": "f6200681b265563b",
"name": "Lower",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 510,
"y": 120,
"wires": [
[
"7c8d261e5f6d0998"
]
]
},
{
"id": "83830bf4b0698084",
"type": "mqtt in",
"z": "f6200681b265563b",
"name": "TankT1",
"topic": "TankT1-Temp/temperature",
"qos": "2",
"datatype": "auto",
"broker": "8aa408ca715b9482",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 90,
"y": 40,
"wires": [
[
"7b73ace1b6cdb759"
]
]
},
{
"id": "49cd2c020d59c024",
"type": "influxdb out",
"z": "f6200681b265563b",
"influxdb": "2e2baf68b726c3bb",
"name": "Temp",
"measurement": "Temp",
"precision": "",
"retentionPolicy": "",
"database": "database",
"precisionV18FluxV20": "ms",
"retentionPolicyV18Flux": "",
"org": "organisation",
"bucket": "bucket",
"x": 250,
"y": 20,
"wires": []
},
{
"id": "bccca8d40a6d63f8",
"type": "switch",
"z": "f6200681b265563b",
"name": "Valve",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "gt",
"v": "TankT1-upper",
"vt": "flow"
},
{
"t": "lte",
"v": "TankT1-lower",
"vt": "flow"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 290,
"y": 100,
"wires": [
[
"bd1daf1565ee885c",
"a95558832e711631"
],
[
"897ba8f3f231a1f0",
"79ef3fe1a242a713"
],
[
"e016d9b888302a93"
]
]
},
{
"id": "e016d9b888302a93",
"type": "debug",
"z": "f6200681b265563b",
"name": "In-Range",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 400,
"y": 160,
"wires": []
},
{
"id": "7b73ace1b6cdb759",
"type": "unit-converter",
"z": "f6200681b265563b",
"category": "temperature",
"inputUnit": "F",
"outputUnit": "F",
"inputField": "payload",
"outputField": "payload",
"inputFieldType": "msg",
"outputFieldType": "msg",
"roundOutputField": true,
"outputFieldDecimals": "1",
"name": "Convert",
"x": 100,
"y": 100,
"wires": [
[
"49cd2c020d59c024",
"876bf077bc5133ad",
"bccca8d40a6d63f8",
"fa5eeedaed9f31e2"
]
]
},
{
"id": "10ba642e6415f895",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "80",
"payloadType": "num",
"x": 130,
"y": 260,
"wires": [
[
"e2df700bbffcf19c"
]
]
},
{
"id": "5845311c332faad2",
"type": "comment",
"z": "f6200681b265563b",
"name": "Upper limit",
"info": "",
"x": 120,
"y": 220,
"wires": []
},
{
"id": "c8ab9cc83c737ff8",
"type": "comment",
"z": "f6200681b265563b",
"name": "Lower limit",
"info": "",
"x": 580,
"y": 220,
"wires": []
},
{
"id": "694b4fe4d5a16fe4",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "75",
"payloadType": "num",
"x": 130,
"y": 300,
"wires": [
[
"e2df700bbffcf19c"
]
]
},
{
"id": "ba17d2d3bffdffdc",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "72",
"payloadType": "num",
"x": 130,
"y": 340,
"wires": [
[
"e2df700bbffcf19c"
]
]
},
{
"id": "d00cc0bcd37d570a",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "77",
"payloadType": "num",
"x": 590,
"y": 260,
"wires": [
[
"281d2c0adf9fce83"
]
]
},
{
"id": "36355bdc381b94de",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "71",
"payloadType": "num",
"x": 590,
"y": 300,
"wires": [
[
"281d2c0adf9fce83"
]
]
},
{
"id": "0d755e19e6dfa112",
"type": "inject",
"z": "f6200681b265563b",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "65",
"payloadType": "num",
"x": 590,
"y": 340,
"wires": [
[
"281d2c0adf9fce83"
]
]
},
{
"id": "e2df700bbffcf19c",
"type": "change",
"z": "f6200681b265563b",
"name": "TankT1-Upper Temp",
"rules": [
{
"t": "set",
"p": "TankT1-upper",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 340,
"y": 260,
"wires": [
[
"b1e07a828296e378"
]
]
},
{
"id": "281d2c0adf9fce83",
"type": "change",
"z": "f6200681b265563b",
"name": "Lower Temp",
"rules": [
{
"t": "set",
"p": "TankT1-lower",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 750,
"y": 260,
"wires": [
[
"e777b04cf3dcd444"
]
]
},
{
"id": "b1e07a828296e378",
"type": "debug",
"z": "f6200681b265563b",
"name": "Upper Temp",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 350,
"y": 320,
"wires": []
},
{
"id": "e777b04cf3dcd444",
"type": "debug",
"z": "f6200681b265563b",
"name": "Lower Temp",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 780,
"y": 330,
"wires": []
},
{
"id": "876bf077bc5133ad",
"type": "debug",
"z": "f6200681b265563b",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 430,
"y": 20,
"wires": []
},
{
"id": "243b63027f532058",
"type": "inject",
"z": "f6200681b265563b",
"name": "TankT1-Upper",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "TankT1-upper",
"payloadType": "flow",
"x": 110,
"y": 500,
"wires": [
[
"d6968efefdcf0985"
]
]
},
{
"id": "d6968efefdcf0985",
"type": "debug",
"z": "f6200681b265563b",
"name": "Tank-T1Setpoints",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 310,
"y": 520,
"wires": []
},
{
"id": "5e673bd9ab566df8",
"type": "inject",
"z": "f6200681b265563b",
"name": "TankT1-Lower",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "TankT1-lower",
"payloadType": "flow",
"x": 110,
"y": 540,
"wires": [
[
"d6968efefdcf0985"
]
]
},
{
"id": "fd8336d590e9745e",
"type": "ui_chart",
"z": "f6200681b265563b",
"name": "",
"group": "a23b2bf2f261c86b",
"order": 1,
"width": "6",
"height": "6",
"label": "Tank-Graph",
"chartType": "line",
"legend": "true",
"xformat": "HH:mm",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "",
"ymax": "",
"removeOlder": 1,
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"outputs": 1,
"useDifferentColor": false,
"className": "",
"x": 90,
"y": 440,
"wires": [
[]
]
},
{
"id": "d6526e17959cd5b1",
"type": "ui_numeric",
"z": "f6200681b265563b",
"name": "",
"label": "TankT1-Upper",
"tooltip": "",
"group": "2df3817beb943471",
"order": 2,
"width": 0,
"height": 0,
"wrap": false,
"passthru": false,
"topic": "topic",
"topicType": "msg",
"format": "{{value}}",
"min": "60",
"max": "75",
"step": 1,
"className": "",
"x": 100,
"y": 380,
"wires": [
[
"e2df700bbffcf19c"
]
]
},
{
"id": "fa5eeedaed9f31e2",
"type": "warp",
"z": "f6200681b265563b",
"name": "",
"scope": [
"fd8336d590e9745e"
],
"destination": "selected",
"x": 240,
"y": 160,
"wires": []
},
{
"id": "73cf7760eb69342b",
"type": "ui_numeric",
"z": "f6200681b265563b",
"name": "TankT1-Lower",
"label": "TankT1-Lower",
"tooltip": "",
"group": "2df3817beb943471",
"order": 2,
"width": 0,
"height": 0,
"wrap": false,
"passthru": true,
"topic": "topic",
"topicType": "msg",
"format": "{{value}}",
"min": "60",
"max": "75",
"step": 1,
"className": "",
"x": 600,
"y": 380,
"wires": [
[
"281d2c0adf9fce83"
]
]
},
{
"id": "8aa408ca715b9482",
"type": "mqtt-broker",
"name": "MQTTBroker",
"broker": "localhost",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"sessionExpiry": ""
},
{
"id": "2e2baf68b726c3bb",
"type": "influxdb",
"hostname": "127.0.0.1",
"port": "8086",
"protocol": "http",
"database": "sensors",
"name": "Sensors",
"usetls": false,
"tls": "",
"influxdbVersion": "1.x",
"url": "http://localhost:8086",
"rejectUnauthorized": true
},
{
"id": "a23b2bf2f261c86b",
"type": "ui_group",
"name": "Graph",
"tab": "75e2c4a4bae21b23",
"order": 1,
"disp": true,
"width": "6",
"collapse": false,
"className": ""
},
{
"id": "2df3817beb943471",
"type": "ui_group",
"name": "TankT1-Setpoints",
"tab": "75e2c4a4bae21b23",
"order": 2,
"disp": true,
"width": "6",
"collapse": false,
"className": ""
},
{
"id": "75e2c4a4bae21b23",
"type": "ui_tab",
"name": "Home",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]