WiFi Temperature Sensor

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
  • NodeMCU
  • MAX31856
  • K-Type Thermocouple
Software
  • Arduino IDE
  • ESP8266 board library
  • Temperature Sensor (code below)
  • Adafruit_MAX31856 library (code below)
  • Android App
Schematics

Sensor wiring diagram.

system.JPG

MAX31856 Schematic


Capture.JPG


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 code
a. 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 /hello
10. 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.
  1. Remove the debug serial print statements.
  2. 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.
After playing around with this temperature sensor for a bit, I already have 3 or 4 real life projects I would like to use it for. The initial one to monitor my smoker, for this one I would use a delay of 10 - 30 seconds, but I would also like to use the sensor to monitor my pipes in my house, every winter they freeze, I could use this sensor to notify me that they are close to freezing, this application I would use the deep sleep of 15 - 30 mins.

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]

Blog entry information

Author
cybermah
Views
1,407
Last update

More entries in General

More entries from cybermah

  • Impact Sensor
    Introduction My project is to build an impact sensor using the IMU of...

Share this entry

Top