Couldn’t sleep so thought I’d put this in here as a work in progress…
About This Project
Before moving back to Canada, I lived for 10 years in the deep south of Texas and Alabama. Needless to say, I grew a fondness for the delectable smoked meats there, namely Texas brisket, and Southern pulled pork.
I would often spend lazy Sundays smoking beef, pork butts, and ribs in a simple drum smoker over several beers and college football. Well that all changed when I moved back to Canada and the winter temperatures plummet to way below zero!!
My current smoker feeds wood pellets into a hot box with an ignitor and a fan to get the pellets started and create convection flow around the meat. My current controller is open loop, meaning there is no automatic adjustment of the hot box temperature when external factors change. Alberta weather is impossible to predict!
On a long smoke, the internal temperature can change by as much as 70 degrees. Too much, so I decided to build something better that I can monitor from inside, on the couch, drinking beers and watching college football.
The project operates on a state machine and implements a PID loop.
When START pressed, do the following:
Set running state
Turn FAN on.
Turn IGNITOR ON
Start timer to turn off IGNITER after X seconds
Start PID loop
When STOP pressed, do the following:
Set shutting down state
Turn PID off
Start cool down timer
Turn off fan
PID operation
Monitor hot box temperature and adjust Auger feed rate to maintain setpoint
Monitors
Monitor ambient and hot box temperatures
Show states of operation:
running
shutting down
fan
auger
ignitor
hopper low
What’s Connected
MKR1000 with a 1200mAH Lithium Polymer backup battery - this is in case the GFCI trips due to a hard rain.
MAX31855 SPI based thermocouple amplifier - provides ambient (cold junction) and hot box temp
K Type Thermocouple connected to the MAX31855 - mounted in centre of hot box
4 port relay board - controls the fan, igniter, auger, and a spare
hopper low switch - alarms when the hopper is getting empty
- Need to add power loss detection alarm
- Perhaps other more complex alarms like failed to ignite
Triggers & Alerts
Hopper low alarm - out of fuel, Bob
Over-temp Alarm - Oh Lord, there’s a fire
Out of control Alarm - Temperature is not tracking with setpoint
Scheduling
Haven’t used yet, but I could easily add a schedule to warm up the smoker before I get home, or do a rest, or stay warm program.
Dashboard Screenshots
Code
//#define CAYENNE_DEBUG // Uncomment to show debug messages
#define CAYENNE_PRINT Serial // Comment this out to disable prints and save space
#include <WiFi101.h>
#include <CayenneMKR1000.h>
#include <Timer.h>
#include <PID_v1.h>
#include <SPI.h>
#include <MAX31855_SPI.h>
//Define Variables we'll be connecting to
double Setpoint, Input, Output,PID_Input;
#define AugerPin 2
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,0.5,1,5, DIRECT);
int WindowSize = 30000;
unsigned long windowStartTime;
byte cs = 0; //chip select is DIO 0
double internal_temp;
double coupler_temp;
MAX31855_SPI *max31855;
int running = 0;
Timer t;
// Cayenne authentication token. This should be obtained from the Cayenne Dashboard.
char token[] = "";
//char token[] = "";
// Your network name and password.
char ssid[] = "";
char password[] = "";
void setup()
{
max31855 = new MAX31855_SPI(cs);
SPI.begin();
//relays
pinMode(1,OUTPUT);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
//setup the pid
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint = 100;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
Serial.begin(9600);
Cayenne.begin(token, ssid, password);
}
void loop()
{
internal_temp = max31855->readInternal();
internal_temp = internal_temp * 9 / 5 + 32;
coupler_temp = max31855->read();
coupler_temp = coupler_temp * 9 / 5 + 32;
Cayenne.run();
t.update();
if(running)
{
Input = coupler_temp;
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
unsigned long now = millis();
if(now - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if(Output > now - windowStartTime) digitalWrite(AugerPin,1);
else digitalWrite(AugerPin,0);
}
else digitalWrite(AugerPin,0);
}
//setpoint
CAYENNE_IN(V0)
{
Setpoint = getValue.asInt()/1000;
Serial.print("Setpoint:");
Serial.println(Setpoint);
}
//cold junction temp
CAYENNE_OUT(V1)
{
Cayenne.virtualWrite(V1,internal_temp);
}
//thermocouple temp
CAYENNE_OUT(V2)
{
Cayenne.virtualWrite(V2,coupler_temp);
}
//start button
CAYENNE_IN(V3)
{
if (getValue.asInt())
{
running = 1;
//indicate running
Cayenne.virtualWrite(V8,1);
//clear start button
Cayenne.virtualWrite(V3,0);
//start fan
digitalWrite(3,1);
//indicate fan running
Cayenne.virtualWrite(V7,1);
//start ignitor cycle
ignite();
}
}
//shutdown button
CAYENNE_IN(V4)
{
if (getValue.asInt())
{
running = 0;
//indicate shutting down
Cayenne.virtualWrite(V8,0);
Cayenne.virtualWrite(V9,1);
//do some stuff
t.after(5000,shutdown);
//clear shutdown button
Cayenne.virtualWrite(V4,0);
}
}
//hopper low
CAYENNE_OUT(V6)
{
Cayenne.virtualWrite(V6,digitalRead(2));
}
void shutdown()
{
//check temp is cool
//send error messages, etc.
//turn off fan
//clear internal variables
//ignitor
Cayenne.virtualWrite(V5,0);
//auger
Cayenne.virtualWrite(V6,0);
//fan
Cayenne.virtualWrite(V7,0);
//indicate no longer running
Cayenne.virtualWrite(V9,0);
}
void ignite()
{
//indicate ignitor on
Cayenne.virtualWrite(V5,1);
//actually start the ignitor
digitalWrite(1,1);
//set callback timer
t.after(10000,ignitor_off);
}
void ignitor_off()
{
//turn off the ignitor
digitalWrite(1,0);
//check temperature
//alert if not hot enough
//indicate ignitor off
Cayenne.virtualWrite(V5,0);
}
void auger_time()
{
digitalWrite(AugerPin,1);
Cayenne.virtualWrite(V6,1);
delay(1000);
digitalWrite(AugerPin,0);
Cayenne.virtualWrite(V6,0);
}
Photos of the Project
Need to wire it up once it’s a little warmer. Still sub-zero here.
Video
Soon!