Project showcase
Complete PID Electric Smoker Control with Bluetooth

Complete PID Electric Smoker Control with Bluetooth © GPL3+

Take the work (and guesswork) out of smoking meat to perfection.

  • 3,487 views
  • 3 comments
  • 10 respects

Components and supplies

About this project

As a retired guy looking to keep my mind challenged, I ran across the Arduino concept and decided to jump in. After learning all the basics my first truly useful project was this smoker controller. It works well, and I use it often so decided to share it. The smoker I use is a cheap charcoal box from Walmart that I easily converted with a 1500w electric heating coil from Amazon ($39) but the controller will work with any electric smoker. It takes all the work (and guesswork) out of smoking meat. It makes a very interesting, inexpensive, and rewarding Arduino project.

The project:

The controller offers some helpful and convenient features including the ability to monitor the smoking process from inside the house using an Android smartphone or pad. The desired smoking temperature along with the desired internal meat temperature is entered on a 4x4 keypad and the controller takes over from there. It continuously monitors and PID controls the process until the desired internal meat temperature is reached. It then stops the cycle and sends a message that dinner is ready.

The materials:

Inside the control box:

1 Arduino uno microcontroller board

2 Max6675 thermocouple controllers

2 K-type thermocouples

1 4x4 keypad

1 2x16 lcd display

1 HC-06 Bluetooth sending unit -- Requires a free BT Terminal app(NUDGE ME)from playstore

1 5v switch mode power supply (5v DC wall charger)

1 5v buzzer

1 enclosure easily built from 1/8' plywood- 6"L x 4.5"W x 3"D

misc. simple connectors, jumpers and resistors (Google one wire keypad - Arduino)

Inside the junction box:

1 Relay 5v SPDT 20A (from Sparkfun)

1 Transistor 2N3904

1 Diode IN 4148

2 Resistors 1k

1 Resistor 10k

1 Red LED

1 5v power supply (usb wall charger)

1 120v wall outlet (from Lowes)

1 Plastic junction box big enough to fit the wall outlet and the relay board (from Lowes)

Most materials were purchased from Amazon or eBay. The total cost of the project is around $65 plus any electric smoker.

The Functions:

1. Maximizes smoker internal temperature to 320 DegF to prevent "runaway" internal temp.

2. Prompts for input of desired smoking temp.

3. Prompts for input of desired internal meat temp.

4. Provides display of actual internal smoker temp.

5. Provides display of actual internal meat temp.

6. Provides stable PID control of set smoker temperature until desired meat temperature is reached.

7. Shuts down power to heating coil when desired meat temperature is reached.

8. Displays message "CYCLE COMPLETE" on upper line when desired meat temperature is reached.

9. Displays message "ENJOY DINNER!" on lower line when desired meat temperature is reached.

10 Provides an audible alert when desired meat temperature is reached

11 Sends status information to Android device via the HC-06 Bluetooth dongle and the Serial port. Requires a BT Terminal app(NUDGE ME)on Phone or Tablet

12 Sends massage to Android device (via Bluetooth) when the desired meat temperature has been reached.

Pins used on Arduino board as follows:

Pin 0 Rx from HC-06 Bluetooth sender

Pin 1 Tx from HC-06 Bluetooth sender

Pin 7 to buzzer +

Pin 8 to control connector

Pin 9 to MAX6675 meat thermocouple

Pin 10 to MAX6675 smoker thermocouple

Pin 12 to both MAX6675

Pin 13 to both MAX6675

Pin A5 to KB and Display board

Pin A4 to KB and Display board

Pin A0 to KB and Display board

5volt power to KB and Display board

5volt power to both Max6675

3.3volt power to HC-06 Bluetooth sender

Ground connections:

from HC-06 Bluetooth sender

from buzzer -

from both MAX6675

from control connector

from KB and Display board

Code

Arduino based electric smoker controllerArduino
// Note: The format offered here does not allow sufficient space on one line
// to accomidate lengthy comments. Some changes may be necessary in the form
// of "//" if the code is to be cut and pasted but may be ok if pasted into 
// the Arduino compiler

//				Start of Arduino Sketch:

#include <LiquidCrystal_I2C.h> // Library for I2C LCD
#include <OnewireKeypad.h>     // OneWireKeypad Library

char KEYS[] = {                // Define keys values of Keypad
  '1', '2', '3',
  '4', '5', '6',
  '7', '8', '9',
  '*', '0', '#'};

#include <SPI.h>                //The two max6675 thermocouples use SPI communications
#include <Thermocouple.h>       //This is the max6675 library that works (could not use "include max6675.h" library)
#define csTC1 9                 //chip select for MAX6675 #1 (SPI)--Smoker temperature--TC1--Orange wire 
#define csTC2 10                //chip select for MAX6675 #2 (SPI)--Meat temperature--TC3--Blue wire
#include <PID_v1.h>             //Library for implementing PID control of the set Smoker temperature
#include <Wire.h>               // Allows the use of the I2C bus
Thermocouple tc1 = Thermocouple(csTC1);  //Identify Thermocouple (from library) as Smoker pin 9
Thermocouple tc2 = Thermocouple(csTC2);  //Identify Thermocouple (from library) as Smoker pin 10
OnewireKeypad <Print, 12 > Keypad(Serial, KEYS, 4, 3, A0, 4700, 1000 );  // Defines keypad as a 4 row, 3 column device //with pin A0 input along with the voltage dividing resistance value.
                                                             
LiquidCrystal_I2C lcd(0x3F, 16, 2); // Provides the I2C Bus address and defines the LCD as a 16 char, 2 line device
double Input;            // declare Input to be a double variable because the PID control library uses double (not interger) variables
double Input2;
double Input3;
double InputAve;    
int RelayPin = 8;        // declare pin8 for relay control
int alert = 7;           // declare pin7 for alert control
const int tempMax = 320; // declare tempMax to be a constant 320 (degreeF)as the maximum temperature the smoker can reach
double tempSmoke = 0;    // declare tempSmoke to be a double variable of the internal temp. of the smoker (DegF) read from thermocouple1
int tempMeat = 0;        // declare tempMeat to be an interger value of the internal temp. of the meat being smoked (DegF) read from thermocouple2
int tempMeat1 = 0;
int tempMeat2 = 0;
int tempMeatAve = 0;     // tempMeatAve is the average of three tc2 readings to increase the accuracy of the actual meat temp reading
int keypress = 0;        // Set to 0 to eliminate any residual values from previous cycles
int keypress1 = 0;
int keypress2 = 0;
double Setpoint;         // declare 'Setpoint' as the value entered from the keypad as the desired maximum internal smoker temp.
int SetMeatTemp;         // declare SetMeatTemp as the value entered from the kaypad as the desired maximum internal meat temp.
char Stop=0;             // Sets the variable 'Stop' to zero to enable use of the 'while' function
char Str1[15] = "CYCLE COMPLETE";  // declare a character string variable to be used at the end of the smoking cycle
char Str2[15] = "ENJOY DINNER!!";  // declare a character string variable to be used at the end of the smoking cycle
double  Output;                    //Define Variables we'll be connecting to for PID control
int Input1=Input;        // declare 'Input1' as an integer so the places past the decimal are dropped for the Android (BT) display
int Setpoint1=Setpoint;  // declare 'Setpoint1' as an integer so the places past the decimal are dropped for the Android (BT) display
PID myPID(&InputAve, &Output, &Setpoint,150,1,1, DIRECT); //Specify the links and initial tuning parameters for PID control
int WindowSize = 3500;
unsigned long windowStartTime;


void setup ()
{
  
  Serial.begin(9600);
  windowStartTime = millis();

  myPID.SetOutputLimits(0, WindowSize);  //tell the PID to range between 0 and the full window size
  
  myPID.SetMode(AUTOMATIC);              //activate the PID
  pinMode(RelayPin, OUTPUT);             //declare pin8 as an output to the 120v relay to turn power on or off to the heating coil
  lcd.init();
  lcd.backlight();
  Wire.begin();
  Keypad.SetHoldTime(100);
  Keypad.Getkey();
  lcd.begin(16, 2);
  lcd.clear();           
  pinMode(alert, OUTPUT);                // declare pin7 as output for the alert
  lcd.print("SMOKE TEMP?");              //Displays 'SMOKE TEMP?' on LCD
                       
  delay(100);                            //Allows everything to get set
}
void loop()
{ // The following section of the code reads the desired temperature for the smoker and the meat and sets up a 3 digit integer using
  //  (int number = 100 * int1 + 10 * int2 + int3) for the variables 'Setpoint' and 'SetMeatTemp'.

  // 1st digit of the desired smoker temperature:

  while (Stop == 0) {   // Allows void loop to be executed in segments to control when events happen. Without 'while' the ketpress is a random entry.
    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(13, 0);

      keypress = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress = keypress - '0';
      lcd.print(keypress);
      Stop = 1;
    }
  }

  //2nd digit smoke:
  while (Stop == 1) {
    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(14, 0);
      keypress1 = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress1 = keypress1 - '0';
      lcd.print(keypress1);
      Stop = 2;
    }
  }
  //3rd digit smoke:
  while (Stop == 2) {
    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(15, 0);
      keypress2 = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress2 = keypress2 - '0';
      lcd.print(keypress2);
      Stop = 3;
    }
  }

  while (Stop == 3) {
    Setpoint = 100 * keypress + 10 * keypress1 + keypress2; // Combines the three entered digits into one (3 digit) variable called 'SetSmokeTemp'.

    lcd.setCursor(0, 1);
    delay(10);
    lcd.print("MEAT TEMP?");                            //Displays 'MEAT TEMP' on LCD
    Stop = 4;
  }
  // 1st digit of the desired meat temperature:
  while (Stop == 4) { // Allows void loop to be executed in segments to control when events happen

    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(13, 1);
      keypress = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress = keypress - '0';
      lcd.print(keypress);
      Stop = 5;
    }
  }
  //2nd digit meat:
  while (Stop == 5) {
    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(14, 1);
      keypress1 = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress1 = keypress1 - '0';
      lcd.print(keypress1);
      Stop = 6;
    }
  }

  //3rd digit meat:
  while (Stop == 6) {
    if ((Keypad.Key_State() == 3))  // not pressed = 0, pressed = 1, released = 2,  held = 3
    {
      lcd.setCursor(15, 1);
      keypress2 = Keypad.Getkey();
      while ((Keypad.Key_State())) {} // Stay here until Key is held down
      keypress2 = keypress2 - '0';
      SetMeatTemp = 100 * keypress + 10 * keypress1 + keypress2; //Combines the 3 entered digits into one (3 digit) variable called 'SetMeatTemp'.
      lcd.print(keypress2);
      Stop = 7;
    }
  }
  
  delay(50);                  // Provides a delay before the cycle begins
 
  Input = (tc1.readF()-19);    //'Input' is the reading of the actual internal smoker temperature adjusted(-19deg)to match the Redi reading(at225deg)
  delay(350);
  
  Input2=(tc1.readF()-19);
  delay(350);
  
  Input3=(tc1.readF()-19);
  delay(350);
  
  InputAve=(Input+Input2+Input3)/3;  //The average of 3 readings is a bit more accurate
  
  if (InputAve>335){InputAve=225;}  //Prevents a 'flier' from shutting down the program (max temp 320)
  
  delay(350);                 //the Max 6675 board is slow and should not be read more than 3 times per second
  tempMeat = (tc2.readF()); //The reading from Thermocouple2 becomes the variable 'tempMeat' adjustment not needed to match the Redi reading(at165deg)
 
  delay(350);                 //the Max 6675 board is slow and should not be read more than 3 times per second
  tempMeat1 = (tc2.readF());
  
  delay(350);
  tempMeat2 = (tc2.readF());
 
  delay(350);
  if(tempMeat>tempMeat1+5||tempMeat<tempMeat1-5){tempMeat=100;tempMeat1=100;Serial.print("flier1 ");} //prevents 'fliers' from adversely affecting    //the program
  if(tempMeat>tempMeat2+5||tempMeat<tempMeat2-5){tempMeat=100;tempMeat2=100;Serial.print("flier2");}  //prevents' fliers' from adversely affecting //the program
  tempMeatAve = (tempMeat+tempMeat1+tempMeat2)/3;                          //Accuracy improved by averaging readings
  
  if(tempMeatAve>SetMeatTemp+10){tempMeatAve=150;Serial.print("flier3");}  //prevents 'fliers' from adversely affecting the program
 

                  // The following 7 lines turns the output pin on/off based on PID output

  myPID.Compute();  
  
  unsigned long now = millis();
  
  if(now - windowStartTime>WindowSize)
  { 
    windowStartTime += WindowSize;  //time to shift the Relay Window
  }
  if(Output > (now - windowStartTime)){ 
   digitalWrite(RelayPin, HIGH);Serial.println("ON"); 
    }
  else {digitalWrite(RelayPin,LOW);Serial.println("OFF");}//}
                       
    lcd.clear();                     // The following 17 lines set up the LCD display to indicate the Set & Actual temperatures
    lcd.setCursor(0, 0);
    lcd.print("SKset");
    lcd.setCursor(5, 0);
    lcd.print(Setpoint);
    lcd.setCursor(9, 0);
    lcd.print("ACT");
    lcd.setCursor(13, 0);
    lcd.print(InputAve);
    lcd.setCursor(0, 1);
    lcd.print("MTset");
    lcd.setCursor(5, 1);
    lcd.print(SetMeatTemp);
    lcd.setCursor(9, 1);
    lcd.print("ACT");
    lcd.setCursor(13, 1);
    lcd.print(tempMeatAve);
    
    Serial.print("SmokerSetTemp=");  // All "Serial.print" and "Serial.println" commands are to send status of smoker to Android BT device
    Setpoint1=Setpoint;
    Serial.print(Setpoint1);
    Serial.print("   ");
    Serial.print("ActualTemp=");
    Input1=InputAve;
    Serial.print(Input1);             
    Serial.println();
    Serial.println();
    Serial.print("MeatSetTemp  =  ");
    Serial.print(SetMeatTemp);
    Serial.print("   ");
    Serial.print("ActualMeatTemp=");
    Serial.print(tempMeatAve);
    Serial.println();
    Serial.println();
    Serial.println(); 
    Serial.println();
    Serial.println();
    Serial.println();
    Serial.println();
    Serial.println();
    Serial.println();       
    delay(50);
    
  if (InputAve>=tempMax)                       // The following 8 lines monitor the maximum temperature of 320deg, shuts down the cycle, 
    {digitalWrite(RelayPin, LOW);           //                                                          sends an alert to the display, and buzzer
                                           
    lcd.clear();                            
    lcd.setCursor(0,0); 
    lcd.print("TEMPERATURE OUT"); 
    lcd.setCursor(0,1);
    lcd.print(" OF CONTROL!!!");
    digitalWrite(alert, HIGH);}   
  
  if (tempMeatAve >= SetMeatTemp)            // When tempMeat(from MAX6675(2)(thermocouple in meat))equals the meat set temp turn smoker coil OFF,
                                             // indicate CYCLE COMPLETE on display, sound the Alert, and stop the Smoker cycle
  {
    digitalWrite(RelayPin, LOW);             //"Stops"the smoking cycle (until the meat temp drops below the meat set temp)
    Serial.println("                      DINNER IS READY");  //Sends message to Android BT device
    Serial.println("                     COME AND GET IT!");  //Sends message to Android BT device
    Serial.println();
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(Str1);                         // print "CYCLE COMPLETE" on first line of LCD display
    lcd.setCursor(0, 1);
    lcd.print(Str2);                         // print "ENJOY DINNER!!" on second line of LCD display
    digitalWrite(alert, HIGH);               // Sets off the alert buzzer 
    delay(150);
    digitalWrite(alert, LOW);                // Provides a short 'beep-beep' instead of an annoying constant single'beeeeeeeep'
    delay(150);
    digitalWrite(alert, HIGH);
    delay(150);
    digitalWrite(alert, LOW);
    delay(3000);}
    } 
            

Comments

Similar projects you might like

Servo Control with TV Remote Control

Project showcase by eldo85

  • 5,594 views
  • 5 comments
  • 17 respects

Control the Speed of Brushless DC Motor Using Bluetooth

Project tutorial by mohitmehlawat

  • 3,489 views
  • 0 comments
  • 13 respects

Arduino Control AC Water Heater temperature

Project tutorial by Mohannad Rawashdeh

  • 9,039 views
  • 0 comments
  • 6 respects

Arduino Bluetooth Car Control

by TayfMavi

  • 4,927 views
  • 1 comment
  • 11 respects

Bluetooth Control Multitap

Project showcase by gledel and 윤원호

  • 1,621 views
  • 0 comments
  • 5 respects

RFID Based Automatic Door System

Project showcase by Robodia Technology

  • 35,764 views
  • 20 comments
  • 97 respects
Add projectSign up / Login