Automated Chicken Coop pt. 9 – Remotely Controlling The Coop pt. 8 “Node-Red and Reading the Temperature”

Reading Temperature

One of the requirements we had for our Automated Chicken coop was being able to read the temperature of the coop and react accordingly to it.  So breakout your pocket book and grab the following items because in this post we are adding the ability to record temperature from our coop!

Materials :

1 – DS18B20   We want the water proof version with a cable already attached.

1 – Prototyping Breadboard (go ahead and get a variable power supply for it, this will come in handy later).

1 – Box of Jumper Wires (get assortment, we will use male to male in this tutorial)

1 – Soldering Iron (can be 30 watt pen iron)

1 – roll of lead free** solder w/ rosin core

1 – 4.7k resistor (you can get a grab bag of resistors on ebay or amazon for fairly cheap and will have more than you’ll use for quite awhile.)

OPTIONAL (but recommended) 

1 – 3Pin Stackable Header***
1 – Variable Bench Top Power Supply****  
1 – Set of Helping Hands

1 – Multimeter*****  


ALL NOTES ON MATERIALS

** If you are new to soldering, get leaded solder to ease in making solid solder connections.  Lead Free solder is harder to use as it does not flow as easily.  No matter which type you choose, always solder in a well ventilated area with a fan blowing fumes away from your work.

*** I recommend finding an assortment box on a site such as amazon, you can also use snap/cutable 1 row headers and cut the size you need from them.  In later projects we will be using headers of different sizes.

**** You don’t need this to begin with, but if you plan on continuing electronics projects it is a very handy tool to have.  A good 12v 5A Wall wart can also substitute this.

*****  OF ALL THE OPTIONAL EQUIPMENT I MOST HIGHLY RECOMMEND YOU ALREADY HAVE THIS!!!!!!  A MULTIMETER CAN HELP YOU DETERMINE IF ELECTRICITY IS FLOWING CORRECTLY AS WELL AS MEASURE THE CURRENT AND VOLTAGE TO PREVENT OVER SUPPLYING VOLTAGE TO A COMPONENT!!!

 

TUTORIAL START

So far I haven’t talked about your workspace.  Now is the time to do so.  From here on out, you need to have a place to work that is free of distractions and provides you plenty of space to work.

Soldering and working with electricity can be a dangerous hobby.  Soldering Irons reach extremely high temperatures and electricity of course can at best – hurt you if handled incorrectly, and at worse – KILL YOU.  

Take all necessary precautions when working with either.  I take no responsibility if you are injured or worse from this point forward.

Making the Connections

Up until now we have handled code exclusively when taking about our NodeMCU boards.  Now its time to use the electronics of the boards to perform actions when told to by code.

Get out your breadboard and put your NodeMCU in the center section (see image below).  The NodeMCU pins should slide into the holes in the breadboard, you may have to use a slight amount of force to set the board completely.

Ignore the LED in the picture above, but pay attention to how the board is placed.  If you look closely, you can see there are rows of pin holes with two groups of rows on either side of a center strip.   To the top, and bottom the  2 rows with color are where power(red) and ground(blue) is applied.  The next picture explains in further detail.

Related image

If you look closely you can see the light grey horizontal lines connecting pins on either side of the center notch in this photo.  Those pins are connected, meaning any electrical signal sent in a pin, that signal also goes to all the other pins connected by that grey line.

For more information on breadboards I highly recommend you read the following site til you are comfortable moving ahead.

http://www.robotplatform.com/tools/breadboard/breadboard.html

Now that you’ve set your NodeMCU in your breadboard, look closely at your NodeMCU on the top.  You should be able to see small letterings next to each of the pin solder points.  These markings tell us the “PinOut” of the NodeMCU.  When you work with any microcontroller, including arduino, study the PinOut schematic of the board so you know what to reference when coding.  Below I’ve included a graphic of the NodeMCU 12-E pinout.

Image result for nodemcu 12 - e

Set the breadboard aside for a moment, and unpack your DS18B20 thermometer.  At one end you will see a silver bullet looking piece where the actual themometer is held and on the other end you will see 3 wires, generally these wires are red, yellow, and black.  The red wire represents “power” the black “ground” and the yellow “data”.

Take your three pin header and carefully solder each wire to an individual pin on the header.  If you chose not to get the header, sacrifice two of your female to female jumper cables by cutting them in half, stripping back some of the insulation and soldering the DS18B20 wires to once each.

Take your male to male jumpers and connect the DS18B20 to the NodeMCU board in the following layout.

Connect the DS18B20 black (ground) to and row with a NodeMCU GND pin.

Connect the DS18B20 red (power) to any row with a NodeMCU 3v3 pin.

Connect the DS18B20 yellow (data) to the NodeMCU D1 pin. (If you look back at the PinOut Diagram you can see D1 equates to GPIO 5, which in code is what we will refer to when we assign a pinout to the ONE_WIRE_BUS.)

One last thing, take your 4.7k resistor, and connect the yellow and red wires together using this resistor.

Coding the NodeMCU to Read Temperature

Open the Sketch we’ve been working on in arduino thus far.  Our DS18B20 uses two new libraries.  Search for and install the OneWire & DallasTemperature libraries then include them in your code like so.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

Now we need to declare our instance like we did before with our PubSubClient.

Under the declared instances we created before add the following lines.

// For Temperature
#define ONE_WIRE_BUS 5
char temperatureString[6];
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

Now we will create a new function to be called to get the temperature.  At the bottom of your code insert the following function.

float getTemperatureF()

{ float tempC; float tempF; do { DS18B20.requestTemperatures(); tempC = DS18B20.getTempCByIndex(0); delay(2500); Serial.println(tempC); } while (tempC == 85.0 || tempC == (-127.0)); // Convert to Farhenheit tempF = ((tempC * 1.8)+32); return tempF; }

Finally add these lines to your loop for now so we can test our DS18B20

float currentTempF = getTemperatureF();
Serial.println(currentTempF);

Open your serial monitor and connect your NodeMCU to your computer while it is still in the breadboard.  Upload the sketch to your NodeMCU.  You should see it repeat two numbers at a set interval of about 2 seconds.  The first number is the temperature in Celcius, and the second number in Farhenheit.

Grip the silver part of the DS18B20 and watch at the temperature changes.

If you only see a constant “-127.0” disconnect the NodeMCU, check your connections and then plug in the NodeMCU and watch the serial monitor again.  Once you have established the DS18B20 is successfully reporting the correct temperature, remove the previous two lines of code we added last.

Node-RED Control and Logging

Now lets move back to our Raspberry Pi setups.   Click on Node-RED as seen in the following image.  This will open a terminal window.  If you read the information in the window it will tell you to point your browser to a web address (ie. 192.168.254.200:1880) if you type this in your browser, you will be brought to the Node-RED application.

You can type in the address given to you in any browser on any computer connected to your network if you would rather work on your regular computer at this point, or on a laptop near your workspace.

At this point, its best that we start using descriptive names for our MQTT topics.  For instance, in my own setup I use the following naming convention

ChickenCoop/(SUBTOPIC)  (ie.  ChickenCoop/Temperature)

and for every SUBTOPIC I also have a second SubTopic for sending commands such as

ChickenCoop/Temperature/Command

Later on when we incorporate other parts of the automated coop, we’ll expand these topics further – such as “ChickenCoop/Door/Status”.

For now, decide on your naming convention, or use mine and write down the topic names you will use.  Remember to stick to your naming convention as you go along to make things much easier on yourself.

So first, we need to set up Node-Red to request the temperature from our NodeMCU.  We’ll design our Node-Red flows, then edit our NodeMCU code to accept the command and respond.

Inside Node-Red to the left are “Nodes” you can think of Nodes as functions, you’ll need to supply information to the Node, and most Nodes will return information as well.

Lets start by adding a MQTT node from under the input heading.  Once you have dragged it into your flow, double click on it to open it’s properties.  Since we are on our actual MQTT Broker machine, the “Server” field should be prefilled with the information we need there.  If it is not, provide the Raspberry PI static IP and add “:1883” to the end of it.

This node will subscribe to the ChickenCoop/Temperature topic, and when a message is sent to this topic it will deliver this topic to the next Node.

Go ahead and add the following Nodes – Trigger, MQTT Output, and Debug Output.  Now we need to tell Node-Red in what order these Nodes will be accessed.  You’ll see what looks like a small check box on the Nodes.  Checkboxes to the Left are input boxes, those to the right are Output boxes.

Connect the Nodes as shown in the following image by clicking the checkboxes and dragging lines to connect them.

Double click the Trigger Node and set the delay to the amount of time you would like to pass between Checking the Coop Temperature.  In the image below you can see I set my own to 15mins.  Configure the rest of the properties as shown in the image below.

Now double click the MQTT Out Node and Configure it with the topic you will use as a Command Topic, (in the image, I used my topic “ChickenCoop/Temperature/Command” ) set the QoS to 1 and give the Node A descriptive name.

Lastly, to display the message we received in Node-Red add one more Debug Output.  Connect this Output to the MQTT IN node.

Open up your NodeMCU sketch – its time to make some changes to our code!

First – delete the lines we added in the last portion from the loop() function.

Inside the reconnect() function change “test/topic1” to the name of your command topic.  In my case – “ChickenCoop/Temperature/Command”.

Inside the setup() function add the following line below existing code.  This tells the NodeMCU to immediately connect to the MQTT server.

reconnect();

Go into your reconnect() function and add these lines inside the IF part of the IF/ELSE statement after the client.subscribe lines  This will tell the ESP to report the temperature as soon as it has established a connection with the MQTT Broker.

float temperature = getTemperatureF();
String tempString = String(temperature); 
sendMsg("ChickenCoop/Temperature", tempString);

Now go into our callback() function and change the first part of our IF/ELSE statement to set topicSwitch to 1 whenever we receive a message on the command topic (ie. “ChickenCoop/Temperature/Command”).

Under case 1: of the switch statement we now need to tell the NodeMCU to send the temperature back.  Copy the last three lines we added to the setup() function (hint: – float & sendMsg) and replace the code inside the case with it.

Lastly, what should happen if say – the power goes out to the Raspberry PI and router, but not to the coop if you are using an alternative energy source like I plan to?  As our code sits right now – once the Raspberry PI went down, the NodeMCU would keep going along as if nothing had happened.  Lets change that by editing the code in our loop() function.  Delete all the code inside the current loop() function and replace it with the code below.  You can easily test this bit of code if your router/modem has a button to turn off WiFi.

//We want to check if the WiFi is connected before we try 
//to reconnect to the broker we'll include this if 
//statement to reconnect 
if (WiFi.status() != WL_CONNECTED) { 
setup_wifi();
 }

//This checks to make sure the MQTT server is connected at all times. Since my plans are to power 
//the chicken coop via alternative energy in the end, the Raspberry PI and the router could lose power 
//when the ChickenCoop has not. This will check the connection periodically and attempt to reconnect 
//to if it no longer has connection the MQTT Broker.
 if (!client.loop()) { 
Serial.print("Client disconnected..."); 
reconnect(); 
} 

Now go back to Node-Red and click Deploy in the upper right corner while your flow is visible.  After doing so, check your code for errors using the Compile(check) button, then upload the code to the NodeMCU.  Whenever it starts you can see the temperature appear in the debug tab of Node-Red.

Bonus test – If your Router/Modem has a button that can turn off WiFi, open your Serial Terminal and then turn off your WiFi.  The NodeMCU should print a line saying “client disconnected” and start trying to reconnect to the MQTT Broker.  Turn back on your WiFi and watch as it connects back to the MQTT Broker.

CONGRATULATIONS!!!  If everything is right, you should now be communicating with your NodeMCU and receiving Communications back!

As always – here is the full Code for review.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// WiFi and MQTT variables
const char* ssid = "YOURWIFISSID";
const char* password = "YOURWIFIPASSWORD";
const char* mqtt_server = "YOURRASPBERYPIHOSTNAME/IPADDRESS";

//MQTT and ESP Setup

WiFiClient espClient;
PubSubClient client(espClient);

// For Temperature
#define ONE_WIRE_BUS 5
char temperatureString[6];
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

void setup() {

Serial.begin(115200);

setup_wifi();

client.setServer(mqtt_server, 1883);

client.setCallback(callback);

reconnect();

}

void loop() {

//We want to check if the WiFi is connected before we try 
//to reconnect to the broker we'll include this if 
//statement to reconnect 
if (WiFi.status() != WL_CONNECTED) { 
setup_wifi();
 }
//This checks to make sure the MQTT server is connected at all times.  Since my plans are to power 
//the chicken coop via alternative energy in the end, the Raspberry PI and the router could lose power
//when the ChickenCoop has not.  This will check the connection periodically and attempt to reconnect
//to if it no longer has connection the MQTT Broker.
if (!client.loop()) {
    Serial.print("Client disconnected...");
    reconnect();
  } 



}

void setup_wifi() {
delay(20);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi Connected");
Serial.println("IP Address is: ");
Serial.println(WiFi.localIP());
Serial.println("");

}

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP8266 Client")) {
Serial.println("connected");
// ... and subscribe to topic
client.subscribe("ChickenCoop/Temperature/Command");
client.subscribe("test/topic2");
client.subscribe("test/topic3");
float temperature = getTemperatureF(); 
String tempString = String(temperature); 
sendMsg("ChickenCoop/Temperature", tempString);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}

void callback(char* topic, byte* payload, unsigned int length)
{

int topicSwitch;
String strTopic = String((char*)topic);
//Determine which topic the message was sent to and
//set the topicSwitch Variable to a number representing
//that topic.
if (strTopic == "ChickenCoop/Temperature/Command"){
topicSwitch = 1;
}else if (strTopic == "test/topic2") {
topicSwitch = 2;
}else if (strTopic == "test/topic3") {
topicSwitch = 3;
}else {
topicSwitch = 4;
}
switch (topicSwitch) {
case 1:
{
//Response to messages sent on the "ChickenCoop/Temperature/Command" topic
float temperature = getTemperatureF();
String tempString = String(temperature);
sendMsg("ChickenCoop/Temperature", tempString);
break;
}
case 2:
{
// Response to messages sent on the "test/topic2" topic
sendMsg("test/test2", "Received a Message on test/topic2");
break;
}
case 3:
{
//Response to messages sent on the "test/topic3" topic
Serial.println("The " + strTopic + " message was received");
break;
}

}

}

void sendMsg(String loTopic, String loMsg){

String topicToSend = loTopic;
String msgToSend = loMsg;

if (client.publish((char*) topicToSend.c_str(), (char*) msgToSend.c_str()) )
{
Serial.println("Publish Succeeded!");
}
else
{
Serial.println("Publish Failed!");
}

return;

}

float getTemperatureF(){

float tempC;
float tempF;
do {
DS18B20.requestTemperatures();
tempC = DS18B20.getTempCByIndex(0);
delay(300);
Serial.println(tempC);
}
while (tempC == 85.0 || tempC == (-127.0));

// Convert to Farhenheit

tempF = ((tempC * 1.8)+32);

return tempF;

}

Leave a Reply

Your email address will not be published. Required fields are marked *