Arduino UNO Thermal Water Bath
The temperature is read through a DS18B20 sensor and sent to the PID node to provide a power output. The output is then scaled according to the power of the element used.
In order to use the One-Wire sensor, ConfigurableFirmata is required with OneWireFirmata installed.
The frequency of measurements has to be changed in the time stamp node as well as in the sensor node.
Once the user temperature is entered on the UI, the PID will provide the relay with a PWM signal.
For changing the Arduino UNO output frequency to match the relay frequency band, see https://arduino-info.wikispaces.com/Arduino-PWM-Frequency
The top part of the flow writes the data in a CSV format for analysis.
[{"id":"53531fa.dc0a7e","type":"debug","z":"88e67d95.ac93a","name":"","active":false,"console":"false","complete":"payload","x":870,"y":60,"wires":[]},{"id":"f8d6f6cd.fc3f08","type":"file","z":"88e67d95.ac93a","name":"Write to file","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","x":1130,"y":160,"wires":[]},{"id":"85a108b7.e4bd38","type":"inject","z":"88e67d95.ac93a","name":"Timestamp (1sec)","topic":"timestamp","payload":"","payloadType":"date","repeat":"0.00001","crontab":"","once":true,"x":170,"y":160,"wires":[["e7f977d5.faf2b8"]]},{"id":"59ab7823.21e0b8","type":"template","z":"88e67d95.ac93a","name":"Convert to CSV","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.timestamp}} , {{payload.temperature}} , {{payload.power}};","x":880,"y":160,"wires":[["13106650.2cd02a","f8d6f6cd.fc3f08"]]},{"id":"e7f977d5.faf2b8","type":"function","z":"88e67d95.ac93a","name":"timeConvert","func":"//create date object from timestamp injected in\nvar dt = new Date(msg.payload); \n\n\n//Create timestamp with only the time, no date, information\nmsg.payload = {\n timestamp: dt.getHours() + ':' + \ndt.getMinutes() + ':' + dt.getSeconds()\n}\n\n//Get the month information out\nvar month = dt.getMonth() + 1; \n\n//Create Filename that data will be saved to\nmsg.filename = dt.getFullYear() + '_' + month \n+ '_' + dt.getDate() + \n'_tempLog.txt';\n\n//Convert log name to string - required for saveFile node\nmsg.filename = msg.filename.toString();\n\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":160,"wires":[["5ccf0055.e583","f0a02529.e7d178"]]},{"id":"5ccf0055.e583","type":"function","z":"88e67d95.ac93a","name":"Join Data Streams","func":"/*\nThis file is based on the flow supplied at \nhttp://flows.nodered.org/flow/8ba7f90f3ea8d92b1e01\nby mharizanov\n\nAll sensors that you have added will need to\nto be added to the code below\n\n*/\ncontext.data = context.data || new Object();\n\n//Add all\n//Wait for information and store it when it comes\nswitch (msg.topic) {\n case \"temperature\":\n context.data.temperature = msg.payload;\n msg = null;\n break;\n case \"power\":\n context.data.power = msg.payload;\n msg = null;\n break;\n case \"timestamp\":\n context.data.timestamp = msg.payload.timestamp;\n context.filename = msg.filename;\n msg = null;\n break;\n \n default:\n msg = null;\n \tbreak;\n}\n\n//When all the data bins are filled, send out the information in one clump\nif(context.data.temperature != null && context.data.timestamp != null && context.data.power != null) {\n msg = new Object();\n msg.payload = context.data;\n msg.filename = context.filename;\n context.data=null;\n\treturn msg;\n\t\n} else return null; //msg;\n\n\n\n\n\n\n\n","outputs":1,"noerr":0,"x":630,"y":160,"wires":[["59ab7823.21e0b8","53531fa.dc0a7e"]]},{"id":"13106650.2cd02a","type":"debug","z":"88e67d95.ac93a","name":"","active":false,"console":"false","complete":"payload","x":1130,"y":60,"wires":[]},{"id":"f0a02529.e7d178","type":"debug","z":"88e67d95.ac93a","name":"","active":false,"console":"false","complete":"filename","x":610,"y":60,"wires":[]},{"id":"87945c44.7878f","type":"debug","z":"88e67d95.ac93a","name":"Actual Temperature","active":true,"console":"false","complete":"payload","x":630,"y":260,"wires":[]},{"id":"c2e1cda7.d4fda","type":"johnny5","z":"88e67d95.ac93a","name":"Sensor","func":"var temperature = new five.Temperature({\n controller: \"DS18B20\",\n pin: \"2\",\n freq: 1000\n });\n \ntemperature.on(\"data\", function() {\n freq = 1000,\n node.send({topic: \"temperature\", payload: this.celsius});\n});\n \n","board":"1b419f06.8dbb81","noerr":0,"x":300,"y":259,"wires":[["5ccf0055.e583","87945c44.7878f","dde09e99.c04e7","b97b7c22.ed16f","29fa915c.f021ee"]]},{"id":"dc02b15.6be9d5","type":"ui_text_input","z":"88e67d95.ac93a","name":"User Temperature","label":"User Temperature","group":"5a3fc73c.6044b8","order":0,"width":0,"height":0,"passthru":false,"mode":"text","delay":"0","topic":"setpoint","x":290,"y":420,"wires":[["95a0692b.a495b8","337d15ef.5d210a","b97b7c22.ed16f","29fa915c.f021ee"]]},{"id":"95a0692b.a495b8","type":"ui_text","z":"88e67d95.ac93a","group":"5a3fc73c.6044b8","order":0,"width":0,"height":0,"name":"","label":"User Temperature: ","format":"{{msg.payload}}","layout":"row-spread","x":290,"y":500,"wires":[]},{"id":"9812d33.bcc1a3","type":"ui_gauge","z":"88e67d95.ac93a","name":"Power Output","group":"5acf17c2.470f38","order":0,"width":"6","height":"8","gtype":"gage","title":"Gauge","label":"W","format":"Power","min":0,"max":"2500","colors":["#00ff00","#00ff00","#00ff00"],"seg1":"","seg2":"","x":620,"y":580,"wires":[]},{"id":"7af61527.f2b8fc","type":"function","z":"88e67d95.ac93a","name":"Convert Power","func":"var p = msg.payload;\n\nP = p * 2500\n\nnode.send({topic: \"power\" , payload: P});","outputs":1,"noerr":0,"x":620,"y":500,"wires":[["9812d33.bcc1a3","5ccf0055.e583"]]},{"id":"1b41607.6b8ada","type":"function","z":"88e67d95.ac93a","name":"Convert to PWM","func":"var p = msg.payload;\n\nPw = Math.round(p * 255);\n\nnode.send({payload: Pw});","outputs":1,"noerr":0,"x":800,"y":420,"wires":[["85d3256b.881d58","8726e22b.6c9fd"]]},{"id":"dde09e99.c04e7","type":"ui_text","z":"88e67d95.ac93a","group":"5a3fc73c.6044b8","order":0,"width":0,"height":0,"name":"Actual Temperature","label":"Actual Temperature: ","format":"{{msg.payload}}","layout":"row-spread","x":340,"y":340,"wires":[]},{"id":"337d15ef.5d210a","type":"debug","z":"88e67d95.ac93a","name":"","active":true,"console":"false","complete":"false","x":290,"y":580,"wires":[]},{"id":"85d3256b.881d58","type":"debug","z":"88e67d95.ac93a","name":"","active":true,"console":"false","complete":"false","x":850,"y":500,"wires":[]},{"id":"b97b7c22.ed16f","type":"ui_chart","z":"88e67d95.ac93a","name":"","group":"5a3fc73c.6044b8","order":0,"width":0,"height":0,"label":"Temperature","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"15","ymax":"60","removeOlder":"30","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"x":610,"y":340,"wires":[[],[]]},{"id":"8726e22b.6c9fd","type":"gpio out","z":"88e67d95.ac93a","name":"Relay : D5","state":"PWM","pin":"5","i2cDelay":"0","i2cAddress":"","i2cRegister":"","outputs":0,"board":"1b419f06.8dbb81","x":1010,"y":420,"wires":[]},{"id":"29fa915c.f021ee","type":"PID","z":"88e67d95.ac93a","name":"PID","setpoint":"","pb":"8","ti":"55","td":"18","integral_default":"0.01","smooth_factor":3,"max_interval":"1","enable":"1","disabled_op":"1","x":590,"y":420,"wires":[["7af61527.f2b8fc","1b41607.6b8ada"]]},{"id":"1b419f06.8dbb81","type":"nodebot","z":"","name":"COM4_port","username":"","password":"","boardType":"firmata","serialportName":"COM4","connectionType":"local","mqttServer":"","socketServer":"","pubTopic":"","subTopic":"","tcpHost":"","tcpPort":"","sparkId":"","sparkToken":"","beanId":"","impId":"","meshbluServer":"https://meshblu.octoblu.com","uuid":"","token":"","sendUuid":""},{"id":"5a3fc73c.6044b8","type":"ui_group","z":"","name":"1","tab":"cde153a3.be9cf","disp":true,"width":"6"},{"id":"5acf17c2.470f38","type":"ui_group","z":"","name":"1","tab":"cde153a3.be9cf","disp":true,"width":"6"},{"id":"cde153a3.be9cf","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}]