IMT3 Environmental Monitoring Pt.2

Getting Started with Node-RED

https://nodered.org/docs/getting-started/ is as good as anywhere to get started. There are also plenty of YouTube clips to watch, so I won’t repeat too much here.

I chose to run Node-RED locally on my Windows 10 laptop so my first step was to download and install a supported prerequisite version of Node.js which will also include npm (Node Package Manager).

npm is the worlds largest Software Registry containing over 800,000 code packages. It is free to use and Open-source developers use npm to share their software.

npm includes a CLI (Command Line Client) that we will use to download and install software.

Having installed Node.js open Windows PowerShell to execute the npm cli command to install Node-RED

  npm install -g --unsafe-perm node-red

The command installs Node-RED as a global module along with its dependencies.

Once installed as a global module we can use the node-red command to start Node-RED in a terminal.  Ctrl-C or closing the terminal window will stop Node-RED.

You can then access the Node-RED editor by pointing your browser at http://localhost:1880/

To access the Node-RED Dashboard point your browser at http://localhost:1881/

By default, Projects are disabled 🙁 , so brush up on your Vi skills* as we need to go and edit settings.js file located in the .node-red directory. *other editors are available.

Just remember to press escape key, colon, w q bang when done!  … now where did I drag that up from, I hadn’t used Vi in years!

After an initial foray into Node-RED, I realised I would need to use Projects within Node-RED. A pre-req for this is Git. With that installed I was good to create my first Project.

I was surprised how quickly I was able get some meaningful results and was soon using npm to add nodes from the Node-RED library for the Dashboard, Arduino and much more. It wasn’t long before I had my first Dashboard displaying the output of the BME280 sensor which looked like the following:

My first Node-RED Dashboard display

An early comment from our dear friend Mil Dave asked “What’s the Dew Point“? … thanks Dave !

Google to the rescue, however the Dewpoint calculation formulae found on the web look pretty scary. Fortunately a search of the Node-RED library found a flow with a dewpoint function defined that I was able to adapt to my flow. A snapshot of the flow follows as it is now beginning to take shape and looks like this:

Node-RED Flow

The green debug nodes are useful to follow the message as they progress through the flow, the debug output can be displayed in the debug window, the system console or as node status appearing just below the debug node

The data from the Arduino arrives on the Serial node which is configured for the com port the Arduino is connected to. I’ve found it easier to determine the relevant com port from the Arduino IDE rather than via control panel and device manager. Also the ‘Get board info’ from the IDE has prove very useful when running Node-RED on MAC OS.

Double clicking any node will open up an Edit window to let you configure each node

Connected to the Serial node is a Split Node. This splits the incoming message into a sequence of messages and is setup to split the message when it finds a comma.

The message is passed to the next node which is a function node which contains some Javascript to give a variable name to each of the values received from the Arduino.

var newMsg = {};
var Sensor = {
    S1C: 0, 
    S1F: 0,
    S2C: 0,
    S2F: 0,
    BT: 0,
    BH: 0,
    BP: 0,

};

context.data = context.data || {};

switch(msg.parts.index){
    case 0:
        context.data.S1C = parseFloat(msg.payload);
        msg = null;
        break;
        
    case 1:
        context.data.S1F = parseFloat(msg.payload);
        msg = null;
        break;
        
    case 2:
        context.data.S2C = parseFloat(msg.payload);
        msg = null;
        break;
        
    case 3:
        context.data.S2F = parseFloat(msg.payload);
        msg = null;
        break;
    
   case 4:
        context.data.BT = parseFloat(msg.payload);
        msg = null;
        break;
     
    case 5:
        context.data.BH = parseFloat(msg.payload);
        msg = null;
        break;
       
    case 6:
        context.data.BP = parseFloat(msg.payload);
        msg = null;
        break;
}

AllData = context.data.S1C &&
          context.data.S1F &&
          context.data.S2C &&
          context.data.S2F &&
          context.data.BT &&
          context.data.BH &&
          context.data.BP;


if(AllData){

    Sensor = context.data;
    newMsg = { payload: context.data,
    topic: 'DS18B20' };
    context.data = null;
    return newMsg;
}
else
    return msg;

The next Function node Splits these seven values and presents them on a separate output of the node which can then be connected to individual Dashboard Gauges.

var msgS1C = {payload: (msg.payload.S1C).toFixed(2)};
var msgS1F = {payload: (msg.payload.S1F).toFixed(2)};
var msgS2C = {payload: (msg.payload.S2C).toFixed(2)};
var msgS2F = {payload: (msg.payload.S2F).toFixed(2)};
var msgBT = {payload: (msg.payload.BT-1.4).toFixed(1)};
var msgBH = {payload: (msg.payload.BH).toFixed(1)};
var msgBP = {payload: (msg.payload.BP).toFixed(0)};

return [msgS1C, msgS1F, msgS2C, msgS2F, msgBT, msgBH, msgBP];

Having split these values out, the Temperature and Humidity values need to be recombined by the Join node so they can be passed to the Dew Point function node.

var newMsg = {};
var parts = msg.payload.split(",");
var Th = parseFloat(parts[0]);
var Hu = parseFloat(parts[1]);

var temp = -1.0*Th; 
es = 6.112*Math.exp(-1.0*17.67*temp/(243.5 - temp)); 
ed = Hu/100.0*es; 
eln = Math.log(ed/6.112); 
td = -243.5*eln/(eln -17.67);

var Dp = td.toFixed(1);

newMsg = {payload: Dp,
     topic: "DewPoint"};

return newMsg;

The DewPoint is now passed to a Dashboard Gauge node and displayed. The Dashboard currently looks like this:

IMT3 Environmental Dashboard

In Pt.3 we’ll take a look at the flow that controls the Arduino with the 4-Relay Shield that allows us to remotely reset the All Sky Camera, HiTechAstro Wx Stn and control a pair of LED lights to illuminate the rig so we can use ManyCam to monitor the web cams installed in the observatory.

The following is the current Node-RED flow running on the IMT3 MAC Mini

[{"id":"485a96ea.056dd8","type":"tab","label":"Keyestudio 4Relay Shield","disabled":false,"info":""},{"id":"4d3e5207.bd89ec","type":"tab","label":"BME280+DS18B20 Sensing Temp Hum Pa","disabled":false,"info":""},{"id":"db09c4dd.5e1178","type":"ui_group","z":"485a96ea.056dd8","name":"IMT3 - Lights","tab":"ab95e945.1f76e8","disp":true,"width":"6","collapse":true},{"id":"516a9fe4.282a2","type":"ui_group","z":"485a96ea.056dd8","name":"IMT3 - All Sky Camera","tab":"ab95e945.1f76e8","disp":true,"width":"6","collapse":true},{"id":"eb5b4cc2.854a6","type":"ui_group","z":"485a96ea.056dd8","name":"IMT3 - Wx Stn","tab":"ab95e945.1f76e8","disp":true,"width":"6","collapse":true},{"id":"49f0ffe8.38f2c","type":"ui_tab","z":"485a96ea.056dd8","name":"IMT3","icon":"dashboard","order":2,"disabled":false,"hidden":false},{"id":"2acc722b.5e03fe","type":"arduino-board","z":0,"device":"COM3"},{"id":"fce2366f.4a0348","type":"arduino-board","z":0,"device":"COM16"},{"id":"db4cc1fa.86c96","type":"ui_base","theme":{"name":"theme-light","lightTheme":{"default":"#0094CE","baseColor":"#0094CE","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"},"themeState":{"base-color":{"default":"#0094CE","value":"#0094CE","edited":false},"page-titlebar-backgroundColor":{"value":"#0094CE","edited":false},"page-backgroundColor":{"value":"#fafafa","edited":false},"page-sidebar-backgroundColor":{"value":"#ffffff","edited":false},"group-textColor":{"value":"#1bbfff","edited":false},"group-borderColor":{"value":"#ffffff","edited":false},"group-backgroundColor":{"value":"#ffffff","edited":false},"widget-textColor":{"value":"#111111","edited":false},"widget-backgroundColor":{"value":"#0094ce","edited":false},"widget-borderColor":{"value":"#ffffff","edited":false},"base-font":{"value":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"}},"angularTheme":{"primary":"indigo","accents":"blue","warn":"red","background":"grey"}},"site":{"name":"Node-RED Dashboard","hideToolbar":"false","allowSwipe":"true","lockMenu":"false","allowTempTheme":"true","dateFormat":"DD/MM/YYYY","sizes":{"sx":32,"sy":32,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"6954d733.e81b68","type":"ui_group","z":"","name":"Pressure","tab":"","order":1,"disp":true,"width":"6","collapse":true},{"id":"5d6c56a8.ca5f78","type":"ui_group","z":"","name":"Reset Controls","tab":"","order":1,"disp":true,"width":"6","collapse":false},{"id":"ee3a92d7.e92d7","type":"serial-port","z":"","serialport":"COM16","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","waitfor":"","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"},{"id":"d2404ee2.c4a07","type":"ui_group","z":"","name":"Humidity","tab":"","order":2,"disp":true,"width":"6","collapse":true},{"id":"7347531.83debac","type":"ui_group","z":"","name":"Pressure","tab":"","order":3,"disp":true,"width":"6","collapse":true},{"id":"afbeacf6.bf67f","type":"serial-port","z":"","serialport":"COM10","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","waitfor":"","newline":"\\n","bin":"false","out":"char","addchar":"false","responsetimeout":"10000"},{"id":"b645ca7c.5c5078","type":"ui_spacer","name":"spacer","group":"83c91351.079c7","order":7,"width":1,"height":1},{"id":"e04b5df3.8023f","type":"mqtt-broker","broker":"localhost","port":"1883"},{"id":"92218788.cc54e8","type":"serial-port","z":"","serialport":"COM5","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","waitfor":"","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"},{"id":"afd985bb.b6f418","type":"serial-port","z":"","serialport":"COM4","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","waitfor":"","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"},{"id":"93ad4e89.caa2f","type":"ui_group","z":"","name":"Pressure/Temperature","tab":"","disp":true,"width":"12","collapse":false},{"id":"cb031b5a.f51aa8","type":"ui_group","z":"","name":"IMT Monitoring","tab":"","disp":true,"width":"6","collapse":false},{"id":"b5dfb3de.d7e15","type":"ui_group","z":"","name":"Group 1","tab":"","order":4,"disp":true,"width":"6","collapse":false},{"id":"24e8044f.8b1a6c","type":"ui_spacer","name":"spacer","group":"5d6c56a8.ca5f78","order":1,"width":1,"height":1},{"id":"389727bb.3ad738","type":"ui_group","z":"","name":"Reset Controls","tab":"49f0ffe8.38f2c","order":5,"disp":true,"width":"6","collapse":true},{"id":"13d4a243.10dcde","type":"ui_group","z":"","name":"Lighting Controls","tab":"49f0ffe8.38f2c","order":4,"disp":true,"width":"6","collapse":true},{"id":"a776141c.b812f8","type":"ui_spacer","name":"spacer","group":"13d4a243.10dcde","order":3,"width":1,"height":1},{"id":"213ca1a5.2ba5de","type":"ui_group","z":"","name":"BME280 Sensor","tab":"49f0ffe8.38f2c","order":3,"disp":true,"width":"6","collapse":true},{"id":"6168a559.a55b3c","type":"ui_group","z":"","name":"BME280 Temp","tab":"","order":4,"disp":true,"width":"6","collapse":false},{"id":"6339fdd1.0da1c4","type":"ui_group","z":"","name":"BME280 - Temp","tab":"","order":4,"disp":true,"width":"6","collapse":true},{"id":"a0396508.e34c88","type":"ui_group","z":"","name":"Nuc Enclosure","tab":"49f0ffe8.38f2c","order":2,"disp":true,"width":"6","collapse":false},{"id":"7dd8b7bb.d7caf8","type":"ui_group","z":"","name":"MAC Mini","tab":"49f0ffe8.38f2c","order":1,"disp":true,"width":"6","collapse":true},{"id":"832ac20d.e8697","type":"comment","z":"485a96ea.056dd8","name":"Arduino with keystudio 4 relay shield on Com16","info":"Bob T - 15July2019\n\nKeyestudio 4 card shield to control LED lights, \nHiTechAstroDeluxe weather station and \nZWO ASI120MC All Sky Camera ","x":380,"y":60,"wires":[]},{"id":"32d3029b.04bf6e","type":"inject","z":"485a96ea.056dd8","name":"Off","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":125,"y":233,"wires":[["dc4c22db.8f295"]]},{"id":"dc4c22db.8f295","type":"delay","z":"485a96ea.056dd8","name":"de-bounce","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":310,"y":243,"wires":[["a613d3b3.48ad","dacf1794.cdaf98"]]},{"id":"a328ae9b.ccca9","type":"inject","z":"485a96ea.056dd8","name":"On","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":125,"y":263,"wires":[["dc4c22db.8f295"]]},{"id":"a613d3b3.48ad","type":"arduino out","z":"485a96ea.056dd8","name":"ZWO ASI120MC USB reset","pin":"7","state":"OUTPUT","arduino":"2acc722b.5e03fe","x":525,"y":278,"wires":[]},{"id":"a2f0bb4f.f498e8","type":"inject","z":"485a96ea.056dd8","name":"Off","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":463,"wires":[["5cf13b52.04e544"]]},{"id":"310eb06c.aaa6e","type":"inject","z":"485a96ea.056dd8","name":"On","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":493,"wires":[["5cf13b52.04e544"]]},{"id":"15c8ff0d.57b2b1","type":"inject","z":"485a96ea.056dd8","name":"Off","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":125,"y":578,"wires":[["ec59f57e.ea8d18"]]},{"id":"e3cfa58e.302168","type":"inject","z":"485a96ea.056dd8","name":"On","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":125,"y":608,"wires":[["ec59f57e.ea8d18"]]},{"id":"fb823e1b.0ebd","type":"inject","z":"485a96ea.056dd8","name":"Off","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":760,"wires":[["be20e01d.52cbd"]]},{"id":"fc39430.0c43ac","type":"inject","z":"485a96ea.056dd8","name":"On","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":790,"wires":[["be20e01d.52cbd"]]},{"id":"5cf13b52.04e544","type":"delay","z":"485a96ea.056dd8","name":"de-bounce","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":315,"y":478,"wires":[["98563994.c5b588","55b1d5a1.8c01bc"]]},{"id":"ec59f57e.ea8d18","type":"delay","z":"485a96ea.056dd8","name":"de-bounce","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":310,"y":593,"wires":[["ae521b10.9b50e8","8957d695.00a448"]]},{"id":"be20e01d.52cbd","type":"delay","z":"485a96ea.056dd8","name":"de-bounce","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":310,"y":790,"wires":[["d24c85c8.bf2c38","c2d7a57d.cf3388"]]},{"id":"98563994.c5b588","type":"arduino out","z":"485a96ea.056dd8","name":"reserved for Wx Stn reset","pin":"6","state":"OUTPUT","arduino":"2acc722b.5e03fe","x":580,"y":478,"wires":[]},{"id":"ae521b10.9b50e8","type":"arduino out","z":"485a96ea.056dd8","name":"reserved for RED LED lighting","pin":"5","state":"OUTPUT","arduino":"2acc722b.5e03fe","x":595,"y":593,"wires":[]},{"id":"d24c85c8.bf2c38","type":"arduino out","z":"485a96ea.056dd8","name":"White LED Lighting","pin":"4","state":"OUTPUT","arduino":"2acc722b.5e03fe","x":570,"y":790,"wires":[]},{"id":"c2d7a57d.cf3388","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":550,"y":845,"wires":[],"inputLabels":["LED"]},{"id":"dacf1794.cdaf98","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","x":650,"y":218,"wires":[]},{"id":"1363d217.e375ae","type":"ui_switch","z":"485a96ea.056dd8","name":"Switch Relay4","label":"Switch White LEDs on","tooltip":"","group":"13d4a243.10dcde","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":120,"y":850,"wires":[["be20e01d.52cbd"]]},{"id":"96a29cbe.85d93","type":"ui_switch","z":"485a96ea.056dd8","name":"Switch Relay3","label":"Switch RED LEDs on","tooltip":"","group":"13d4a243.10dcde","order":2,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":120,"y":658,"wires":[["ec59f57e.ea8d18"]]},{"id":"55b1d5a1.8c01bc","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","x":550,"y":428,"wires":[]},{"id":"8957d695.00a448","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","x":545,"y":658,"wires":[]},{"id":"4b9ea92f.a5e9e8","type":"ui_button","z":"485a96ea.056dd8","name":"","group":"389727bb.3ad738","order":1,"width":0,"height":0,"passthru":false,"label":"Reset ZWO ASI120MC","tooltip":"Press to reset camera, power will be turned off for 7 seconds","color":"","bgcolor":"","icon":"","payload":"true","payloadType":"bool","topic":"","x":170,"y":113,"wires":[["aaf4a028.f0347","54152099.11ec1"]]},{"id":"aaf4a028.f0347","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":640,"y":113,"wires":[]},{"id":"54152099.11ec1","type":"trigger","z":"485a96ea.056dd8","op1":"1","op2":"0","op1type":"num","op2type":"str","duration":"7","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":345,"y":158,"wires":[["b47fba95.880ac8","dc4c22db.8f295"]]},{"id":"b47fba95.880ac8","type":"debug","z":"485a96ea.056dd8","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":640,"y":158,"wires":[]},{"id":"8c8ddd2.3ba6a2","type":"inject","z":"485a96ea.056dd8","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":125,"y":158,"wires":[["54152099.11ec1"]]},{"id":"17a45757.0f3839","type":"ui_button","z":"485a96ea.056dd8","name":"","group":"389727bb.3ad738","order":1,"width":0,"height":0,"passthru":false,"label":"Reset  Wx Stn","tooltip":"Press to reset Weather Station, power is removed for 7 seconds","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"","x":140,"y":338,"wires":[["ae8f9b64.17ad08"]]},{"id":"ae8f9b64.17ad08","type":"trigger","z":"485a96ea.056dd8","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"7","extend":false,"units":"s","reset":"","bytopic":"all","name":"","x":465,"y":338,"wires":[["5cf13b52.04e544"]]},{"id":"35c5f11a.a6fd2e","type":"inject","z":"485a96ea.056dd8","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":383,"wires":[["ae8f9b64.17ad08"]]},{"id":"ce4ad2aa.33a02","type":"trigger","z":"485a96ea.056dd8","op1":"1","op2":"0","op1type":"str","op2type":"str","duration":"7","extend":false,"units":"min","reset":"","bytopic":"all","name":"","x":360,"y":907,"wires":[["be20e01d.52cbd"]]},{"id":"7bdfc101.255ec","type":"ui_button","z":"485a96ea.056dd8","name":"","group":"13d4a243.10dcde","order":5,"width":0,"height":0,"passthru":false,"label":"White LEDs on Timer","tooltip":"","color":"","bgcolor":"","icon":"","payload":"true","payloadType":"bool","topic":"","x":135,"y":907,"wires":[["ce4ad2aa.33a02"]]},{"id":"7432b57b.2b4fac","type":"serial in","z":"4d3e5207.bd89ec","name":"","serial":"afd985bb.b6f418","x":65,"y":255,"wires":[["fbe3b723.be8138","d6674162.0d89a"]]},{"id":"d968c054.e6532","type":"function","z":"4d3e5207.bd89ec","name":"","func":"var newMsg = {};\nvar Sensor = {\n //   NData: 0, \n    Temp: 0,\n    Humid: 0,\n    Pressure_BME280 : 0,\n\n//    Time: new Date().toString()\n};\n\ncontext.data = context.data || {};\n\nswitch(msg.parts.index){\n    case 0:\n        context.data.NData = parseFloat(msg.payload);\n        msg = null;\n        break;\n    case 1:\n        context.data.Temp = parseFloat(msg.payload);\n        msg = null;\n        break;\n    case 2:\n        context.data.Humid = parseFloat(msg.payload);\n        msg = null;\n        break;\n        \n    case 3:\n        context.data.Pressure_BME280 = parseFloat(msg.payload);\n        msg = null;\n        break;\n        \n\n}\n\n//AllData = context.data.NData &&\nAllData =   context.data.Temp &&\n          context.data.Humid &&\n          context.data.Pressure_BME280;\n       \n        \n         // context.data.Altitud_BMP;\n\nif(AllData){\n //   var time = Date();\n   // context.data.Time = time.toString();\n    Sensor = context.data;\n    newMsg = { payload: context.data,\n    topic: 'Frame Sensor' };\n    context.data = null;\n    return newMsg;\n}\nelse\n    return msg;\n","outputs":1,"noerr":0,"x":455,"y":255,"wires":[["e6be691e.67eed8","f1854d0d.daac6"]]},{"id":"bffe4a25.88d4d8","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":520,"y":120,"wires":[]},{"id":"d6674162.0d89a","type":"split","z":"4d3e5207.bd89ec","name":"","splt":" ","spltType":"str","arraySplt":"3","arraySpltType":"len","stream":false,"addname":"","x":320,"y":255,"wires":[["d968c054.e6532","bffe4a25.88d4d8"]]},{"id":"e6be691e.67eed8","type":"json","z":"4d3e5207.bd89ec","name":"","property":"payload","action":"str","pretty":true,"x":605,"y":255,"wires":[["8c80d979.2751c8"]]},{"id":"8c80d979.2751c8","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":670,"y":360,"wires":[]},{"id":"fbe3b723.be8138","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":195,"y":135,"wires":[]},{"id":"f1854d0d.daac6","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","x":565,"y":180,"wires":[]},{"id":"36f134f3.b00a8c","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":265,"y":345,"wires":[]},{"id":"44c5c387.ca6b1c","type":"serial in","z":"4d3e5207.bd89ec","name":"DS18B20","serial":"afd985bb.b6f418","x":75,"y":420,"wires":[["36f134f3.b00a8c","8e7bff44.7351a"]]},{"id":"8e7bff44.7351a","type":"split","z":"4d3e5207.bd89ec","name":"","splt":",","spltType":"str","arraySplt":"6","arraySpltType":"len","stream":false,"addname":"","x":260,"y":435,"wires":[["42fc1749.2fb2d8","a21c2add.952cd8"]],"inputLabels":["1"],"outputLabels":["3"]},{"id":"42fc1749.2fb2d8","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":630,"y":440,"wires":[]},{"id":"a21c2add.952cd8","type":"function","z":"4d3e5207.bd89ec","name":"Payload Object Sensor","func":"var newMsg = {};\nvar Sensor = {\n    S1C: 0, \n    S1F: 0,\n    S2C: 0,\n    S2F: 0,\n    BT: 0,\n    BH: 0,\n    BP: 0,\n\n//    Time: new Date().toString()\n};\n\ncontext.data = context.data || {};\n\nswitch(msg.parts.index){\n    case 0:\n        context.data.S1C = parseFloat(msg.payload);\n        msg = null;\n        break;\n    case 1:\n        context.data.S1F = parseFloat(msg.payload);\n        msg = null;\n        break;\n    case 2:\n        context.data.S2C = parseFloat(msg.payload);\n        msg = null;\n        break;\n        \n    case 3:\n        context.data.S2F = parseFloat(msg.payload);\n        msg = null;\n        break;\n    \n   case 4:\n      context.data.BT = parseFloat(msg.payload);\n      msg = null;\n      break;\n     \n    case 5:\n        context.data.BH = parseFloat(msg.payload);\n        msg = null;\n        break;\n       \n    case 6:\n        context.data.BP = parseFloat(msg.payload);\n        msg = null;\n        break;\n\n\n}\n\nAllData = context.data.S1C &&\n          context.data.S1F &&\n          context.data.S2C &&\n          context.data.S2F &&\n          context.data.BT &&\n          context.data.BH &&\n          context.data.BP;\n       \n        \n         // context.data.Altitud_BMP;\n\nif(AllData){\n    //var time = Date();\n   // context.data.Time = time.toString();\n    Sensor = context.data;\n    newMsg = { payload: context.data,\n    topic: 'DS18B20' };\n    context.data = null;\n    return newMsg;\n}\nelse\n    return msg;\n\n\n","outputs":1,"noerr":0,"x":400,"y":525,"wires":[["ea728815.3b1928","bf04c7ef.157d88"]]},{"id":"ea728815.3b1928","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":655,"y":525,"wires":[]},{"id":"bf04c7ef.157d88","type":"function","z":"4d3e5207.bd89ec","name":"Split Data","func":"var msgS1C = {payload: (msg.payload.S1C).toFixed(2)};\nvar msgS1F = {payload: (msg.payload.S1F).toFixed(2)};\nvar msgS2C = {payload: (msg.payload.S2C).toFixed(2)};\nvar msgS2F = {payload: (msg.payload.S2F).toFixed(2)};\nvar msgBT = {payload: (msg.payload.BT).toFixed(2)};\nvar msgBH = {payload: (msg.payload.BH).toFixed(2)};\nvar msgBP = {payload: (msg.payload.BP).toFixed(2)};\n\n//var msgS1C = {payload: (msg.payload.S1C).toFixed(2)};\n//var msgS1F = {payload: (msg.payload.S1F).toFixed(2)};\n//var msgS2C = {payload: (msg.payload.S2C).toFixed(2)};\n//var msgS2F = {payload: (msg.payload.S2F).toFixed(2)};\n//var msgBT = {payload: (msg.payload.BT).toFixed(2)};\n//var msgBH = {payload: (msg.payload.BH).toFixed(2)};\n\n\n//var msgbme280_h = {payload: (msg.payload.bme280_h).toFixed(1)};\n//var msgbme280_p = {payload: (msg.payload.bme280_p).toFixed(1)};\n\nreturn [msgS1C, msgS1F, msgS2C, msgS2F, msgBT, msgBH, msgBP];\n//return [msgS1C, msgS1F, msgS2C, msgS2F, msgbme280_t, msgbme280_h, msgbme280_p];\n\n\n\n\n\n//var msgTemp = {payload: msg.payload.Temp};\n//var msgTemp = {payload: (msg.payload.Temp).toFixed(1)};\n//var msgHumid = {payload: msg.payload.Humid};\n//var msgHumid = {payload: (msg.payload.Humid).toFixed(1)};\n//var msgTemp_DS = {payload: msg.payload.Temp_DS};\n//var msgTemp_BMP = {payload: msg.payload.Temp_BMP};\n//var msgPressure_BME = {payload: (msg.payload.Pressure_BME280).toFixed(0)};\n//var msgPressure_BME = {payload: (msg.payload.Pressure_BME280/100000).toFixed(2)};\n//var msgAltitud_BMP = {payload: msg.payload.Altitud_BMP};\n\n//return [msgTemp_DHT11];\n//return [msgTemp, msgHumid, msgPressure_BME];\n//return [msgTemp_DHT11, msgHumid_DHT, msgTemp_DS, msgTemp_BMP, msgPressure_BMP, msgAltitud_BMP ];","outputs":7,"noerr":0,"x":255,"y":750,"wires":[["5a7a2a2.9de7ed4","74244174.a7498"],["1df94d4f.96f153","bc09270c.1c3d38"],["83e8c937.e86d18","b9e2e2e3.e5de6"],["4dc159a8.536488","b3d40b.af729bf8"],["7bf4618d.9e1e2","edca722d.9bc12"],["24655be.0e446a4","76e9dff9.ffc88"],["5e28cc59.1975a4","214f5175.b812fe"]]},{"id":"5a7a2a2.9de7ed4","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":550,"y":615,"wires":[]},{"id":"1df94d4f.96f153","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":535,"y":720,"wires":[]},{"id":"83e8c937.e86d18","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":535,"y":810,"wires":[]},{"id":"4dc159a8.536488","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":480,"y":930,"wires":[]},{"id":"74244174.a7498","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"Mac Mini Enclosure","group":"7dd8b7bb.d7caf8","order":1,"width":0,"height":0,"gtype":"gage","title":"MAC Mini Enclosure","label":"","format":"{{value}}°C","min":0,"max":"50","colors":["#008000","#ff8000","#ff0000"],"seg1":"","seg2":"","x":540,"y":675,"wires":[]},{"id":"bc09270c.1c3d38","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"DS18B20","group":"7dd8b7bb.d7caf8","order":2,"width":0,"height":0,"gtype":"gage","title":"MAC Mini","label":"","format":"{{value}}°F","min":0,"max":"100","colors":["#008000","#ff8000","#ff0000"],"seg1":"","seg2":"","x":475,"y":768,"wires":[]},{"id":"b9e2e2e3.e5de6","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"NUC Enclosure","group":"a0396508.e34c88","order":1,"width":0,"height":0,"gtype":"gage","title":"NUC Enclosure","label":"","format":"{{value}}°C","min":0,"max":"60","colors":["#008000","#ff8000","#ff0000"],"seg1":"","seg2":"","x":515,"y":870,"wires":[]},{"id":"b3d40b.af729bf8","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"DS18B20","group":"a0396508.e34c88","order":1,"width":0,"height":0,"gtype":"gage","title":"NUC","label":"","format":"{{value}}°F","min":0,"max":"100","colors":["#008000","#ff8000","#ff0000"],"seg1":"","seg2":"","x":510,"y":990,"wires":[]},{"id":"7bf4618d.9e1e2","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":480,"y":1060,"wires":[]},{"id":"24655be.0e446a4","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":470,"y":1140,"wires":[]},{"id":"5e28cc59.1975a4","type":"debug","z":"4d3e5207.bd89ec","name":"","active":true,"tosidebar":false,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","x":460,"y":1220,"wires":[]},{"id":"edca722d.9bc12","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"bme280-t","group":"213ca1a5.2ba5de","order":1,"width":0,"height":0,"gtype":"gage","title":"Ambient Temperature","label":"Centigrade","format":"{{value}}°C","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":570,"y":1100,"wires":[]},{"id":"76e9dff9.ffc88","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"bme280-rH","group":"213ca1a5.2ba5de","order":2,"width":0,"height":0,"gtype":"gage","title":"Relative Humdity","label":"rH","format":"{{value}}%","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":620,"y":1200,"wires":[]},{"id":"214f5175.b812fe","type":"ui_gauge","z":"4d3e5207.bd89ec","name":"bme280-p","group":"213ca1a5.2ba5de","order":3,"width":0,"height":0,"gtype":"gage","title":"Air Pressure","label":"mmHg","format":"{{value}}","min":0,"max":"1200","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":610,"y":1300,"wires":[]},{"id":"6b6b4cd9.5a4f54","type":"ui_button","z":"485a96ea.056dd8","name":"","group":"13d4a243.10dcde","order":4,"width":0,"height":0,"passthru":false,"label":"RED LEDs on Timer","tooltip":"","color":"","bgcolor":"","icon":"","payload":"true","payloadType":"bool","topic":"","x":140,"y":700,"wires":[["ec59f57e.ea8d18"]]}]

IMT3 Environmental Monitoring Pt.1

IMT3 Environmental Monitoring Pt.1
Bob Trevan – Aug2019

When Dave, Mark and I first started planning what equipment we were going to install in IMT3 we started with a block diagram of what we thought we were going to install so we could determine the number of USB ports we would need and the power requirements. This soon morphed into much more as we started adding kit to the project.

Although the Observatory is install in the UK and not Spain as was originally planned, we decided we would still need a fair bit of monitoring to allow remote sensing of the local conditions. In particular making sure it was safe to open the shutter for a remote observing session

During AstroFest in Feb 2019 we bought a HiTechAstro Deluxe Weather Station which can be used as an ASCOM safety device to autonomously close the Dome Shutter if rain or cloud is detected. Although we were lead to believe it would directly interface with the Pulsar Dome Controller, this was not the case and required a simple interface consisting of a SPST Relay to control the shutter. Once the Relay is picked the shutter closes and will stay closed until the operator manually resets the state of the relay via the weather station software. The software has a number of options to configure to determine when to close the shutter

Although the Shutter itself has a battery pack that has sufficient capacity to close the shutter in the event of a power outage we decided to add an APC UPS with PowerChute software so provide AC power resilience to critical components. The shutter battery is wirelessly charged when the dome is parked at the end of each observing session.

In addition to the Cloud and Rain sensor, we also have a Sky Quality Meter and All Sky camera mounted on the same pole. The cable run to the pole from the panel inside the dome to which we were mounting various components … MAC Mini, 10-port USB HUB, Power Bricks, etc … is about 10m. The cabling provided with the Weather Station was somewhat shorter than this which meant having to extend it with the challenges of making the external connections water tight.

The HiTechAstro Wx Stn is also a Cloud Sensor utilizing an IR sensor to measure the Sky Temperature and a Dallas DS18B20 to measure Ambient Temperature. The waterproof probe is attached to the underside of the mounting bracket.

For monitoring the Dome Internal conditions I started looking at what we could achieve using an Arduino (*1) with various sensors. Currently we have two Arduinos installed, the first utilizes an Arduino UNO R3 with a Bosch BME280 (*2) Temperature, Humidity and Pressure Sensor and a pair of Dallas DS18B20 (*3) temperature probes for monitoring the internal temperatures of the enclosures housing the MAC Mini and Intel NUC (*4) (more on the NUC later). The current version of code running on this Arduino is provided at the end of this part of the blog.

A second Arduino has a 4-relay shield attached. The relays are used to control two 380 lumens LED lights inside the dome and after modifying a couple of short USB extension leads, breaking into the +5v line, the remaining 2 relays are used to reset the All Sky Camera and HiTechAstro Deluxe Wx Stn, when the need arises (which is all too frequently). This Arduino is programmed to run Standard Firmata code allowing Node-RED to communicate via the serial port and control the relays.

*1   Arduino is an open-source electronics platform based on easy-to-use hardware and software. Arduino boards are able to read inputs – light on a sensor, a finger on a button, or a Twitter message – and turn it into an output – activating a motor, turning on an LED, publishing something online.

The Arduino integrated development environment (IDE) is a cross-platform application (for Windows, macOS, Linux) that is written in the programming language Java, C, C++. It is used to write and upload programs to Arduino compatible boards. User-written code only requires two basic functions, for starting the sketch and the main program loop. For more info see https://en.wikipedia.org/wiki/Arduino_IDE

*2   Bosch BME280
The BME280 is an integrated environmental sensor developed specifically for mobile applications where size and low power consumption are key design constraints. The unit combines individual high linearity, high accuracy sensors for pressure, humidity and temperature in an 8-pin metal-lid 2.5 x 2.5 x 0.93 mm³ LGA package, designed for low current consumption (3.6 μA @1Hz), long term stability and high EMC robustness.

*3   Dallas DS18B20
The DS18B20-PAR digital thermometer provides 9 to 12–bit centigrade temperature measurements and has an alarm function with nonvolatile user-programmable upper and lower trigger points. The DS18B20-PAR communicates over a 1-Wire bus, which by definition requires only one data line (and ground) for communication with a central microprocessor. It has an operating temperature range of –55°C to +100°C and is accurate to ±0.5°C over a range of –10°C to +85°C.

*4   Next Unit of Computing (NUC) is a line of small-form-factor barebone computer kits designed by Intel. The NUC motherboard measures 4 × 4 inches (10.16 × 10.16 cm)

The Bosch BME280 Sensor uses the I2C bus and the Dallas DS18B20 probes use a One-Wire interface. Each of the DS18B20 has a unique internal 64-bit address created during the manufacturing process, so you can just keep adding as many as you need with relative ease.

Currently, every 20 seconds, the Arduino spits out 7 values separated by commas and terminated with a line feed, these are:

  1. DS18B20 Ext sensor Temperatue in °C
  2. DS18B20 Ext sensor Temperature in °F
  3. DS18B20 Int sensor Temperature in °C
  4. DS18B20 Int sensor Temperature in °F
  5. BME280 sensor Temperature in °C
  6. BME280 sensor Humidity in %
  7. BME280 sensor Pressure in mPa

e.g. 27.0000,80.6000,26.0000,78.8000,28.53,43.53,1008.28

Mark also donated a HiTechAstro Hub to the project which is used to control DC power to the Cameras, Focuser, Filter Wheels and potentially Dew Heaters, but with three rigs mounted on the SB Paramount ME-II we were quickly using all available USB Ports and Switched DC power ports available.

After several ‘Hangs’ of the NUC due the to the software packages tested with the All Sky Camera, we added a MAC mini to run the environment applications, leaving the Intel NUC to run the Main Applications to control the mount and Cameras. The Sky X, Sequence Generator Pro etc…

So we now have a number of PC / MAC applications, controlling and displaying various functions of IMT3. But how do we display the Arduino data ?

Working for IBM, Dave had been exposed to Node-RED. Originally developed by IBM, Node-RED is a flow based development tool for visual programming for wiring together hardware devices, APIs and online services as part of the Internet of Things.

Node-RED provides a web browser-based flow editor, which can be used to create Javascript fuctions. The runtime is built on Node.js. The flows created in Node-RED are stored using JSON. Since version 0.14 MQTT nodes can make properly configured TLS connections.

In 2016, IBM contributed Node-RED as an open source JS Foundation project.

One of the Node-RED projects is a dashboard UI for Node-RED, and this is how the Arduino sensor data is displayed, along with the flow that controls the 4 relays on the Arduino Relay Shield.

We have a new vocabulary to learn; IoT, MQTT, node.js, Node-RED, JSON, Arduino, Sketch, Flow and new languages to learn C, C++, Javascript and we haven’t even mentioned the BBC MicroBit or Raspbery Pi and Python 🙂

I’ll describe the Node-RED flows I currently have working and the Dashboard in Pt. 2.

Arduino Code:

/********************************************************************
* Arduino code used for monitoring the Internal Ambient Temperature,
* Humidity and Air Pressure of IMT3 Observatory using a Bosch BME280 sensor
* and two Dallas DS18B20 temperature probes to measure the temperatures of
* the MAC Mini and Intel NUC enclosures.
*
* I have commented out alot of the lines used during development, but left
* them in to help comment the code.
*
* Currently, every 20 seconds, the Arduino spits out 7 values separated by
* commas and terminated with a line feed, these are:
*
* DS18B20 Ext sensor Temperatue in °C
* DS18B20 Ext sensor Temperature in °F
* DS18B20 Int sensor Temperature in °C
* DS18B20 Int sensor Temperature in °F
*
* BME280 sensor Temperature in °C
* BME280 sensor Humidity in %
* BME280 sensor Pressure in mPa
*
* e.g. 27.0000,80.6000,26.0000,78.8000,28.53,43.53,1008.28
*
* The above will be displayed as Gauges on a Node-RED Dashboard.
*
* Bob Trevan August 2019
*******************************************************************/
/******************************************************************
This is a library for the BME280 humidity, temperature & pressure sensor
Designed specifically to work with the Adafruit BME280 Breakout
----> http://www.adafruit.com/products/2650
 These sensors use I2C or SPI to communicate, 2 or 4 pins are required
to interface. The device's I2C address is either 0x76 or 0x77.
 Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products from Adafruit! 
Written by Limor Fried & Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
*******************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

Adafruit_BME280 bme; // I2C
char buffer[60];
// Onewire Reference and assign it to pin 5 on the Arduino
OneWire oneWire(5);
// declare as sensor reference by passing oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// declare the device addresses
//Device 1: 0x28, 0x41, 0x0F, 0x84, 0x1F, 0x13, 0x01, 0x16
//Device 2: 0x28, 0x89, 0x25, 0x6E, 0x1F, 0x13, 0x01, 0x3F

//Device 3: 0x28, 0xAD, 0x43, 0xE2, 0x1B, 0x13, 0x01, 0x8D
//Device 4: 0x28, 0x0B, 0xA9, 0x63, 0x1F, 0x13, 0x01, 0xCC

//Device 5: 0x28, 0x52, 0xDA, 0x71, 0x1F, 0x13, 0x01, 0x68
//Device 6: 0x28, 0xAA, 0xBD, 0x68, 0x3C, 0x14, 0x01, 0x4E

// Select the pair of sensor used with this Arduino, these addresses have previously been read with a separate piece of Arduino code.
DeviceAddress ExtSensor = {0x28, 0xAA, 0xBD, 0x68, 0x3C, 0x14, 0x01, 0x4E};
DeviceAddress IntSensor = {0x28, 0x52, 0xDA, 0x71, 0x1F, 0x13, 0x01, 0x68};

// Variables to hold the temperatures
float ExtC; // originally had one sensor hanging out of my study window
float IntC; // and a second sensor by my desk.

void setup() {
Serial.begin(9600);

// Serial.println(F("BME280 test"));
bool status;
status = bme.begin(0x76); // I2C Address
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}

// Serial.println("-- Default Test --");

Serial.println();

// set the resolution to 9 bit - Valid values are 9, 10, or 11 bit.
sensors.setResolution(ExtSensor, 9);

// confirm that we set that resolution by asking the DS18B20 to repeat it back
//Serial.print("Exterior Sensor Resolution: ");
//Serial.println(sensors.getResolution(ExtSensor), DEC);
//Serial.println();
// set the resolution to 9 bit - Valid values are 9, 10, or 11 bit.

sensors.setResolution(IntSensor, 9);

// confirm that we set that resolution by asking the DS18B20 to repeat it back
//Serial.print("Interior Sensor Resolution: ");
//Serial.println(sensors.getResolution(IntSensor), DEC);
//Serial.println();
}

void loop() {
// Tell the Ext sensor to Measure and Remember the Temperature it Measured
sensors.requestTemperaturesByAddress(ExtSensor); // Send the command to get temperatures
// Get the temperature that you told the sensor to measure

ExtC = sensors.getTempC(ExtSensor);

//Serial.print("Exterior Sensor: ");
//Serial.print("Temp C: ");

Serial.print(ExtC,4); // The four just increases the resolution that is printed
Serial.print(",");

//Serial.print(" Temp F: ");
// The Dallas Temperature Control Libray has a conversion function... we'll use it

Serial.print(DallasTemperature::toFahrenheit(ExtC),4);
Serial.print(",");

// Tell the INT sensor to Measure and Remember the Temperature it Measured sensors.requestTemperaturesByAddress(IntSensor); // Send the command to get temperatures
// Get the temperature that you told the sensor to measure

IntC = sensors.getTempC(IntSensor);

//Serial.print("Interior Sensor: ");
//Serial.print("Temp C: ");

Serial.print(IntC,4); // The four just increases the resolution that is printed
Serial.print(",");

//Serial.print(" Temp F: ");
// The Dallas Temperature Control Libray has a conversion function... we'll use it

Serial.print(DallasTemperature::toFahrenheit(IntC),4);
Serial.print(",");
//Serial.println("\n");
printTemp();
printHum();
printPa();
delay(20000);
}

void printTemp() {
dtostrf(getTemp(),1,2,buffer);

// Serial.print("Temperature = ");

Serial.print(buffer);
Serial.print(",");

// Serial.println(" *C");
}

void printHum() {
dtostrf(getHum(),1,2,buffer);

// Serial.print("Humidity = ");

Serial.print(buffer);
Serial.print(",");

// Serial.println(" %");
}

void printPa() {
dtostrf(getPa(),1,2,buffer);

// Serial.print("Pressure = ");

Serial.println(buffer);

// Serial.println(" hPa");
}

double getTemp(void) {
double t;
t = bme.readTemperature();
return (t);
}

double getHum(void) {
double h;
h = bme.readHumidity();
return (h);
}

double getPa(void) {
double p;
p = (bme.readPressure() / 100.0F);
return (p);
}