Introduction
My project is a Wifi temperature sensor. I was looking for a way to monitor my Smoker. The current wireless one I have, you had to be within 10 feet or it would be out of range. It kinda defeats the purpose of Wireless. I wanted something that I could go anywhere in and around the house and still see what the temperature is.
BOM
Sensor wiring diagram.
MAX31856 Schematic
Instructions
The way the sensor works is the NodeMCU will communicate using SPI to the MAX31856 tempertature sensor which reads the voltage on a thermocouple and converts it to a temperature value in degrees C. Then the NodeMCU will take the value received and put it on an MQTT topic using Wifi. An app, MQTT Dash, will read the topic and display the temperature on your android phone. I have a MQTT server here, but if you use a public MQTT server, you could monitor the temperature anywhere in the world. Not practical for a Smoker, but for monitoring temperature of your home it would work great.
Assemble the hardware as per the fritzing diagram above.
For the code part, I used the Arduino IDE. So download and install it. You will need some libraries added to the IDE in order to program the NodeMCU.
1. Open the IDE
2. Goto File / Preferences
3. In the Additional boards Manager URLs, add the following
4. Click ok
5. Goto Tools
6. Board
7. Board Manager
8. Search for esp8266
9. Click on the esp8266 by ESP8266 Community and install it.
10. Open the Board Manager again and select the NodeMCU 1.0(ESP-12E Module)
11. Your IDE should be ready to program NodeMCUs now.
12. Test by opening the Examples, esp8266, Blink
13. Connect your NodeMCU to your pc
14. Compile and Upload Blink to the board.
15. A blue light should blink on and off. If it does your ready to continue
Now for the code
1. Open the Arduino IDE
2. Select File / New
3. Copy the Temperature sensor code attached
4. Copy the Adafruit-MAX31856 code attached and place it in the same directory as the code above.
5. You can also download the library, but don’t install it in the IDE, we need to make a small change in it.
6. Click on Sketch / Add File and select max31856.cpp
7. Click on Sketch / Add File and select max31856.h
8. The change required in the max31856.cpp
10. Android App
You will notice in the code there are some improvements that should be made to make the sensor more efficient.
The nice part about this sensor is it uses WiFi and mqtt to send the data, this means it is very easy to connect it to a number of home automation systems or even public mqtt brokers for simple monitoring.
Thanks
Dana.
Source Code
My project is a Wifi temperature sensor. I was looking for a way to monitor my Smoker. The current wireless one I have, you had to be within 10 feet or it would be out of range. It kinda defeats the purpose of Wireless. I wanted something that I could go anywhere in and around the house and still see what the temperature is.
BOM
- NodeMCU
- MAX31856
- K-Type Thermocouple
- Arduino IDE
- ESP8266 board library
- Temperature Sensor (code below)
- Adafruit_MAX31856 library (code below)
- Android App
Sensor wiring diagram.
MAX31856 Schematic
Instructions
The way the sensor works is the NodeMCU will communicate using SPI to the MAX31856 tempertature sensor which reads the voltage on a thermocouple and converts it to a temperature value in degrees C. Then the NodeMCU will take the value received and put it on an MQTT topic using Wifi. An app, MQTT Dash, will read the topic and display the temperature on your android phone. I have a MQTT server here, but if you use a public MQTT server, you could monitor the temperature anywhere in the world. Not practical for a Smoker, but for monitoring temperature of your home it would work great.
Assemble the hardware as per the fritzing diagram above.
For the code part, I used the Arduino IDE. So download and install it. You will need some libraries added to the IDE in order to program the NodeMCU.
1. Open the IDE
2. Goto File / Preferences
3. In the Additional boards Manager URLs, add the following
4. Click ok
5. Goto Tools
6. Board
7. Board Manager
8. Search for esp8266
9. Click on the esp8266 by ESP8266 Community and install it.
10. Open the Board Manager again and select the NodeMCU 1.0(ESP-12E Module)
11. Your IDE should be ready to program NodeMCUs now.
12. Test by opening the Examples, esp8266, Blink
13. Connect your NodeMCU to your pc
14. Compile and Upload Blink to the board.
15. A blue light should blink on and off. If it does your ready to continue
Now for the code
1. Open the Arduino IDE
2. Select File / New
3. Copy the Temperature sensor code attached
4. Copy the Adafruit-MAX31856 code attached and place it in the same directory as the code above.
5. You can also download the library, but don’t install it in the IDE, we need to make a small change in it.
6. Click on Sketch / Add File and select max31856.cpp
7. Click on Sketch / Add File and select max31856.h
8. The change required in the max31856.cpp
a. Find the SPISetting entry line 27
b. it should be static SPISettings max31856_spisettings = SPISettings(100000, MSBFIRST, SPI_MODE3);
9. Now for the Sensor codea. Add your SSID and password for your WiFi connection
b. Change the connection information for MQTT. I have my own, but you can find free ones on the web to use
c. Compile and Upload the code to your NodeMCU
d. If you have a MQTT viewer, open it and point to the topic /hello10. Android App
a. Open google play and install MQTT Dash
b. Open the app Hit the plus sign in the upper right corner
c. Enter a name
d. add the address and port of your MQTT server
e. add your username and password to your MQTT server
f. save it.
g. Select your entry you just made
h. Hit the plus symbol
i. Chose Range/progress
j. Give it a name
k. put in the topic /temperature
l. Select the range you plan to monitor
m. Save it.
n. you should start to see the temperature show up now
Conclusion:You will notice in the code there are some improvements that should be made to make the sensor more efficient.
- Remove the debug serial print statements.
- remove the delay() and switch it to ESP.deepsleep. Depending on your sleep time, you could run this sensor over a year without having to change or charge your battery. I have my delay set to 60 seconds at the moment, but that was for testing. Because of the different uses for this sensor, I would adjust this time for the application I'm using it for.
The nice part about this sensor is it uses WiFi and mqtt to send the data, this means it is very easy to connect it to a number of home automation systems or even public mqtt brokers for simple monitoring.
Thanks
Dana.
Source Code
Code:
[FONT=Courier New][SIZE=4]#include <MQTTClient.h>
#include <ESP8266WiFi.h>
#include <SPI.h>
#include "Adafruit_MAX31856.h"
const char ssid[] = "[B]your_ssid[/B]";
const char pass[] = "[B]your_password[/B]";
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
// Use software SPI: CS, DI, DO, CLK
Adafruit_MAX31856 maxim = Adafruit_MAX31856(15, 13, 12,14);
// use hardware SPI, just pass in the CS pin
//Adafruit_MAX31856 maxim = Adafruit_MAX31856(15);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
client.begin("[B]192.168.2.28[/B]", 1883, net);
client.onMessage(messageReceived);
connect();
Serial.println("MAX31856 thermocouple test");
maxim.begin();
maxim.setThermocoupleType(MAX31856_TCTYPE_K);
}
void loop() {
Serial.print("Cold Junction Temp: "); Serial.println(maxim.readCJTemperature());
Serial.print("Thermocouple Temp: "); Serial.println(maxim.readThermocoupleTemperature());
// Check and print any faults
uint8_t fault = maxim.readFault();
if (fault) {
if (fault & MAX31856_FAULT_CJRANGE) Serial.println("Cold Junction Range Fault");
if (fault & MAX31856_FAULT_TCRANGE) Serial.println("Thermocouple Range Fault");
if (fault & MAX31856_FAULT_CJHIGH) Serial.println("Cold Junction High Fault");
if (fault & MAX31856_FAULT_CJLOW) Serial.println("Cold Junction Low Fault");
if (fault & MAX31856_FAULT_TCHIGH) Serial.println("Thermocouple High Fault");
if (fault & MAX31856_FAULT_TCLOW) Serial.println("Thermocouple Low Fault");
if (fault & MAX31856_FAULT_OVUV) Serial.println("Over/Under Voltage Fault");
if (fault & MAX31856_FAULT_OPEN) Serial.println("Thermocouple Open Fault");
}
delay(60000);
client.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!client.connected()) {
connect();
}
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/temperature", String(maxim.readThermocoupleTemperature()));
}
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect("admin", "admin", "admin")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/temperature");
// client.unsubscribe("/temperature");
}[/SIZE][/FONT]
Code:
[FONT=Courier New][SIZE=4]/***************************************************
This is a library for the Adafruit Thermocouple Sensor w/MAX31855K
Designed specifically to work with the Adafruit Thermocouple Sensor
----> https://www.adafruit.com/products/269
These displays use SPI to communicate, 3 pins are required to
interface
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/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#ifndef ADAFRUIT_MAX31856_H
#define ADAFRUIT_MAX31856_H
#define MAX31856_CR0_REG 0x00
#define MAX31856_CR0_AUTOCONVERT 0x80
#define MAX31856_CR0_1SHOT 0x40
#define MAX31856_CR0_OCFAULT1 0x20
#define MAX31856_CR0_OCFAULT0 0x10
#define MAX31856_CR0_CJ 0x08
#define MAX31856_CR0_FAULT 0x04
#define MAX31856_CR0_FAULTCLR 0x02
#define MAX31856_CR1_REG 0x01
#define MAX31856_MASK_REG 0x02
#define MAX31856_CJHF_REG 0x03
#define MAX31856_CJLF_REG 0x04
#define MAX31856_LTHFTH_REG 0x05
#define MAX31856_LTHFTL_REG 0x06
#define MAX31856_LTLFTH_REG 0x07
#define MAX31856_LTLFTL_REG 0x08
#define MAX31856_CJTO_REG 0x09
#define MAX31856_CJTH_REG 0x0A
#define MAX31856_CJTL_REG 0x0B
#define MAX31856_LTCBH_REG 0x0C
#define MAX31856_LTCBM_REG 0x0D
#define MAX31856_LTCBL_REG 0x0E
#define MAX31856_SR_REG 0x0F
#define MAX31856_FAULT_CJRANGE 0x80
#define MAX31856_FAULT_TCRANGE 0x40
#define MAX31856_FAULT_CJHIGH 0x20
#define MAX31856_FAULT_CJLOW 0x10
#define MAX31856_FAULT_TCHIGH 0x08
#define MAX31856_FAULT_TCLOW 0x04
#define MAX31856_FAULT_OVUV 0x02
#define MAX31856_FAULT_OPEN 0x01
typedef enum
{
MAX31856_TCTYPE_B = 0b0000,
MAX31856_TCTYPE_E = 0b0001,
MAX31856_TCTYPE_J = 0b0010,
MAX31856_TCTYPE_K = 0b0011,
MAX31856_TCTYPE_N = 0b0100,
MAX31856_TCTYPE_R = 0b0101,
MAX31856_TCTYPE_S = 0b0110,
MAX31856_TCTYPE_T = 0b0111,
MAX31856_VMODE_G8 = 0b1000,
MAX31856_VMODE_G32 = 0b1100,
} max31856_thermocoupletype_t;
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
class Adafruit_MAX31856 {
public:
Adafruit_MAX31856(int8_t spi_cs, int8_t spi_mosi, int8_t spi_miso, int8_t spi_clk);
Adafruit_MAX31856(int8_t spi_cs);
boolean begin(void);
void setThermocoupleType(max31856_thermocoupletype_t type);
max31856_thermocoupletype_t getThermocoupleType(void);
uint8_t readFault(void);
void oneShotTemperature(void);
float readCJTemperature(void);
float readThermocoupleTemperature(void);
void setTempFaultThreshholds(float flow, float fhigh);
void setColdJunctionFaultThreshholds(int8_t low, int8_t high);
private:
int8_t _sclk, _miso, _mosi, _cs;
void readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n);
uint8_t readRegister8(uint8_t addr);
uint16_t readRegister16(uint8_t addr);
uint32_t readRegister24(uint8_t addr);
void writeRegister8(uint8_t addr, uint8_t reg);
uint8_t spixfer(uint8_t addr);
};
#endif[/SIZE][/FONT]
Code:
[FONT=Courier New][SIZE=4]/***************************************************
This is a library for the Adafruit Thermocouple Sensor w/MAX31856
Designed specifically to work with the Adafruit Thermocouple Sensor
----> https://www.adafruit.com/products/xxxx
These sensors use SPI to communicate, 4 pins are required to
interface
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/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_MAX31856.h"
#ifdef __AVR
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#endif
#include <stdlib.h>
#include <SPI.h>
static SPISettings max31856_spisettings = SPISettings([B]100000, MSBFIRST, SPI_MODE3[/B]);
// Software (bitbang) SPI
Adafruit_MAX31856::Adafruit_MAX31856(int8_t spi_cs, int8_t spi_mosi, int8_t spi_miso, int8_t spi_clk) {
_sclk = spi_clk;
_cs = spi_cs;
_miso = spi_miso;
_mosi = spi_mosi;
pinMode(_cs, OUTPUT);
}
// Hardware SPI init
Adafruit_MAX31856::Adafruit_MAX31856(int8_t spi_cs) {
_cs = spi_cs;
pinMode(_cs, OUTPUT);
_sclk = _miso = _mosi = -1;
}
boolean Adafruit_MAX31856::begin(void) {
digitalWrite(_cs, HIGH);
if (_sclk != -1) {
//define pin modes
pinMode(_sclk, OUTPUT);
pinMode(_mosi, OUTPUT);
pinMode(_miso, INPUT);
} else {
//start and configure hardware SPI
SPI.begin();
}
// assert on any fault
writeRegister8(MAX31856_MASK_REG, 0x0);
writeRegister8(MAX31856_CR0_REG, MAX31856_CR0_OCFAULT0);
setThermocoupleType(MAX31856_TCTYPE_K);
return true;
}
void Adafruit_MAX31856::setThermocoupleType(max31856_thermocoupletype_t type) {
uint8_t t = readRegister8(MAX31856_CR1_REG);
t &= 0xF0; // mask off bottom 4 bits
t |= (uint8_t)type & 0x0F;
Serial.println(t);
writeRegister8(MAX31856_CR1_REG, t);
}
max31856_thermocoupletype_t Adafruit_MAX31856::getThermocoupleType(void) {
uint8_t t = readRegister8(MAX31856_CR1_REG);
Serial.println("what t is:" + t);
t &= 0x0F;
Serial.println(t);
return (max31856_thermocoupletype_t)(t);
}
uint8_t Adafruit_MAX31856::readFault(void) {
return readRegister8(MAX31856_SR_REG);
}
void Adafruit_MAX31856::setColdJunctionFaultThreshholds(int8_t low, int8_t high) {
writeRegister8(MAX31856_CJLF_REG, low);
writeRegister8(MAX31856_CJHF_REG, high);
}
void Adafruit_MAX31856::setTempFaultThreshholds(float flow, float fhigh) {
int16_t low, high;
flow *= 16;
low = flow;
fhigh *= 16;
high = fhigh;
writeRegister8(MAX31856_LTHFTH_REG, high >> 8);
writeRegister8(MAX31856_LTHFTL_REG, high);
writeRegister8(MAX31856_LTLFTH_REG, low >> 8);
writeRegister8(MAX31856_LTLFTL_REG, low);
}
void Adafruit_MAX31856::oneShotTemperature(void) {
writeRegister8(MAX31856_CJTO_REG, 0x0);
uint8_t t = readRegister8(MAX31856_CR0_REG);
t &= ~MAX31856_CR0_AUTOCONVERT; // turn off autoconvert!
t |= MAX31856_CR0_1SHOT;
writeRegister8(MAX31856_CR0_REG, t);
delay(250); // MEME FIX autocalculate based on oversampling
}
float Adafruit_MAX31856::readCJTemperature(void) {
oneShotTemperature();
int16_t temp16 = readRegister16(MAX31856_CJTH_REG);
float tempfloat = temp16;
tempfloat /= 256.0;
return tempfloat;
}
float Adafruit_MAX31856::readThermocoupleTemperature(void) {
oneShotTemperature();
int32_t temp24 = readRegister24(MAX31856_LTCBH_REG);
if (temp24 & 0x800000) {
temp24 |= 0xFF000000; // fix sign
}
temp24 >>= 5; // bottom 5 bits are unused
float tempfloat = temp24;
tempfloat *= 0.0078125;
return tempfloat;
}
/**********************************************/
uint8_t Adafruit_MAX31856::readRegister8(uint8_t addr) {
uint8_t ret = 0;
readRegisterN(addr, &ret, 1);
return ret;
}
uint16_t Adafruit_MAX31856::readRegister16(uint8_t addr) {
uint8_t buffer[2] = {0, 0};
readRegisterN(addr, buffer, 2);
uint16_t ret = buffer[0];
ret <<= 8;
ret |= buffer[1];
return ret;
}
uint32_t Adafruit_MAX31856::readRegister24(uint8_t addr) {
uint8_t buffer[3] = {0, 0, 0};
readRegisterN(addr, buffer, 3);
uint32_t ret = buffer[0];
ret <<= 8;
ret |= buffer[1];
ret <<= 8;
ret |= buffer[2];
return ret;
}
void Adafruit_MAX31856::readRegisterN(uint8_t addr, uint8_t buffer[], uint8_t n) {
addr &= 0x7F; // make sure top bit is not set
if (_sclk == -1)
SPI.beginTransaction(max31856_spisettings);
else
digitalWrite(_sclk, HIGH);
digitalWrite(_cs, LOW);
spixfer(addr);
//Serial.print("$"); Serial.print(addr, HEX); Serial.print(": ");
while (n--) {
buffer[0] = spixfer(0xFF);
//Serial.print(" 0x"); Serial.print(buffer[0], HEX);
buffer++;
}
//Serial.println();
if (_sclk == -1)
SPI.endTransaction();
digitalWrite(_cs, HIGH);
}
void Adafruit_MAX31856::writeRegister8(uint8_t addr, uint8_t data) {
addr |= 0x80; // make sure top bit is set
if (_sclk == -1)
SPI.beginTransaction(max31856_spisettings);
else
digitalWrite(_sclk, HIGH);
digitalWrite(_cs, LOW);
spixfer(addr);
spixfer(data);
//Serial.print("$"); Serial.print(addr, HEX); Serial.print(" = 0x"); Serial.println(data, HEX);
if (_sclk == -1)
SPI.endTransaction();
digitalWrite(_cs, HIGH);
}
uint8_t Adafruit_MAX31856::spixfer(uint8_t x) {
if (_sclk == -1)
return SPI.transfer(x);
// software spi
//Serial.println("Software SPI");
uint8_t reply = 0;
for (int i=7; i>=0; i--) {
reply <<= 1;
digitalWrite(_sclk, LOW);
digitalWrite(_mosi, x & (1<<i));
digitalWrite(_sclk, HIGH);
if (digitalRead(_miso))
reply |= 1;
}
return reply;
}[/SIZE][/FONT]