Modular Temperature Measurement and Logging

Measures temperature using thermistors and logs the data in csv format.

Designed to be modular in nature so that additional temperature sensors can be added easily, with the long term intent to expand the available sensor inputs or outputs.

The temperature information is extracted from a board of your choice (an Arduino board was originally used) using the Johnny-Five node.js library and the custom built Johnny-Five node-red node (available at https://www.npmjs.com/package/node-red-contrib-gpio, with details as to which micro controller boards are supported)

Can be used for any temperature monitoring application, but was built with the intent to log temperature data with a timestamp for research experiments. The data is logged in CSV format for easing importing into more suitable software packages for post-processing and analysis, such as MATLAB or Python.

A more detailed description of how to use this flow can be found at: https://sites.google.com/view/opensourcehardwaresouthafrica

update: 26Feb17: The flow has been modified to initialise the sensors in a seperate node, so that subsequent nodes can record information when promted by the flow. (Previously data recording nodes could not be setup to record data when prompted, as this created a new instance of the sensor each time, resulting in a oveflow of sensor instances).

[{"id":"4dbd840.b7f637c","type":"comment","z":"70268e30.8059c","name":"Notes","info":"This system will record data from the analog channels\non the board of choice (Arduino in this case), \ncombine it into a single data stream and save it\nto text file in a csv format.\n\nIts intent is for the logging of temperature\ndata in research settings, where CSV stored \ninformation is common practice to ease importing \ninto subsequent software used for post-processing \nand detailed analysis such as MATLAB or Python.\n\nThe intent is also that the temperature node can\nbe copied and reused as additional temperature\nchannels are used, with subsequent minimal \nmodification of the downstream nodes.\n","x":1070,"y":180,"wires":[]},{"id":"2d4ac53d.86ee9a","type":"debug","z":"70268e30.8059c","name":"","active":false,"console":"false","complete":"payload","x":978,"y":469,"wires":[]},{"id":"87280f41.eb925","type":"file","z":"70268e30.8059c","name":"Save to Text File","filename":"","appendNewline":true,"createDir":false,"overwriteFile":"false","x":1189,"y":382,"wires":[]},{"id":"a6cdaf5c.4c29a","type":"inject","z":"70268e30.8059c","name":"Timestamp (10sec)","topic":"timestamp","payload":"","payloadType":"date","repeat":"10","crontab":"","once":true,"x":144,"y":399,"wires":[["dfd9234c.1ceef","c73f050d.826b18","680121ea.c7b6c"]]},{"id":"222556b9.19771a","type":"template","z":"70268e30.8059c","name":"Convert to CSV","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{{payload.timestamp}} , {{payload.sensor1}} , {{payload.sensor2}};","x":969,"y":335,"wires":[["87280f41.eb925","a46c2184.b96b4"]]},{"id":"dfd9234c.1ceef","type":"function","z":"70268e30.8059c","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":403,"y":396,"wires":[["843a24ea.ee7188","47a29567.07711c"]]},{"id":"843a24ea.ee7188","type":"function","z":"70268e30.8059c","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 \"sensor1\":\n        context.data.sensor1 = msg.payload;\n        msg = null;\n        break;\n    case \"sensor2\":\n        context.data.sensor2 = 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.sensor1 != null && context.data.sensor2 != null && context.data.timestamp != 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":740,"y":315,"wires":[["222556b9.19771a","2d4ac53d.86ee9a"]]},{"id":"63cc067b.399398","type":"debug","z":"70268e30.8059c","name":"","active":true,"console":"false","complete":"false","x":758,"y":199,"wires":[]},{"id":"a46c2184.b96b4","type":"debug","z":"70268e30.8059c","name":"","active":true,"console":"false","complete":"false","x":1187,"y":307,"wires":[]},{"id":"c73f050d.826b18","type":"function","z":"70268e30.8059c","name":"Temperature Thermistor Sensor1","func":"//Access the sensors you wish to use\nsensorName = \"sensor1\";\nvar sensor = global.get(sensorName);\n\n//Create variables\nvar T;\nvar R;\nvar analogueOut = 0;  //analogue out\n\n// Steinhart-Hart B parameter Equation variables\n//these values are far from the standard and were fitted using an excel sheet\nvar B = 3434;\nvar T0 = 298.15;\nvar rPass = 9.64; //resitance of passive resitor in kOhm\nvar rThermistor = 9.2; //resistance of thermistor at room temperature in kOhm\n\n//Take readings\nanalogueOut =  sensor.scaleTo(0, 1023); //read sensor info, scale to value between 0 and 1023\n//calculate resistance of thermistor\nR = rPass / ((1023 / analogueOut)-1); \n//calculate correspnding temperature in degC of thermistor based on resistance value using Steinhart-Hart equation\n//B parameter version of steinhart equation\nT = 1 / (1/T0 + 1/B*Math.log(R/rThermistor)) - 273.15;\n//Round Number to 2 decimals\nT = Math.round(T * 100) / 100;    \n\n//Send the information out\nnode.send({topic: sensorName , payload: T , id: '2'});  //send inforamtion out of node, attach topic to payload for identification later\n\n \n\n","outputs":1,"noerr":0,"x":460,"y":200,"wires":[["843a24ea.ee7188","63cc067b.399398"]]},{"id":"c3c13b8d.f3cf98","type":"johnny5","z":"70268e30.8059c","name":"Initialise Sensors","func":" //Create all the sensor instances you wish\n //The j5 node is only run once, thus there is no\n //chance of multiple instances being created.\n var sensorA4 = new five.Sensor({\n    pin: \"A4\",\n      });     //read in values from sensor\n var sensorA5 = new five.Sensor({\n    pin: \"A5\",\n      });     //read in values from sensor\n         \n//make sensors available across all function nodes\nglobal.set(\"sensor1\" , sensorA4);  // this is now available to other nodes\nglobal.set(\"sensor2\" , sensorA5);  // this is now available to other nodes","board":"b55b8013.f9367","noerr":0,"x":170,"y":200,"wires":[["c73f050d.826b18","680121ea.c7b6c"]]},{"id":"680121ea.c7b6c","type":"function","z":"70268e30.8059c","name":"Temperature Thermistor Sensor2","func":"//Access the sensors you wish to use\nsensorName = \"sensor2\";\nvar sensor = global.get(sensorName);\n\n\n//Create variables\nvar T;\nvar R;\nvar analogueOut = 0;  //analogue out\n\n// Steinhart-Hart B parameter Equation variables\n//these values are far from the standard and were fitted using an excel sheet\nvar B = 3434;\nvar T0 = 298.15;\nvar rPass = 9.64; //resitance of passive resitor in kOhm\nvar rThermistor = 9.2; //resistance of thermistor at room temperature in kOhm\n\n//Take readings\nanalogueOut =  sensor.scaleTo(0, 1023); //read sensor info, scale to value between 0 and 1023\n//calculate resistance of thermistor\nR = rPass / ((1023 / analogueOut)-1); \n//calculate correspnding temperature in degC of thermistor based on resistance value using Steinhart-Hart equation\n//B parameter version of steinhart equation\nT = 1 / (1/T0 + 1/B*Math.log(R/rThermistor)) - 273.15;\n//Round Number to 2 decimals\nT = Math.round(T * 100) / 100;    \n\n//Send the information out\nnode.send({topic: sensorName , payload: T , id: '2'});  //send inforamtion out of node, attach topic to payload for identification later\n\n\n","outputs":1,"noerr":0,"x":460,"y":260,"wires":[["843a24ea.ee7188","37a85418.61441c"]]},{"id":"37a85418.61441c","type":"debug","z":"70268e30.8059c","name":"","active":true,"console":"false","complete":"false","x":750,"y":260,"wires":[]},{"id":"5bb6a9a7.d96a08","type":"comment","z":"70268e30.8059c","name":"Modification Notes","info":"The 'Join Data Dtreams' and 'Convert to CSV\" nodes need to be \nupdated with the names of the sensors actually used.\nIn this example those names are 'sensor1' and\n'sensor2', as seen in the J5 node.","x":400,"y":140,"wires":[]},{"id":"ac877e7b.daeb7","type":"comment","z":"70268e30.8059c","name":"J5 Node Connecting Notes","info":"The J5 node will not reconnect to the board after a \nchange has been made and it has been deployed.\n\nYou will have to restart node-red to allow the J5 node\nto connect.","x":170,"y":140,"wires":[]},{"id":"47a29567.07711c","type":"debug","z":"70268e30.8059c","name":"","active":true,"console":"false","complete":"filename","x":690,"y":460,"wires":[]},{"id":"b55b8013.f9367","type":"nodebot","z":"70268e30.8059c","name":"COM5_port","username":"","password":"","boardType":"firmata","serialportName":"COM5","connectionType":"local","mqttServer":"","socketServer":"","pubTopic":"","subTopic":"","tcpHost":"","tcpPort":"","sparkId":"","sparkToken":"","beanId":"","impId":"","meshbluServer":"https://meshblu.octoblu.com","uuid":"","token":"","sendUuid":""}]

Flow Info

Created 8 years ago
Updated 7 years, 1 month ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • comment (x3)
  • debug (x5)
  • file (x1)
  • function (x4)
  • inject (x1)
  • template (x1)
Other
  • johnny5 (x1)
  • nodebot (x1)

Tags

  • arduino
  • johnny-five
  • monitoring
  • research
  • R&D
  • data
  • logging
  • temperature
  • thermistor
  • sensor
  • johnny5
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option