WIFI Meat Temperature Probe MK2 - mySQL & Graphing Additions

This is an update to WIFI Meat Temperature Probe



The original temp probe worked ok but was not perfect, you had to connect to the web page hosted on the Meat Probe WEMOS ESP32 itself. So it was very limited to what you can do with it.
 
Due to having some time available while under Covid19 lock down, I changed the software.

The Meat Probe WEMOS ESP32 now works very differently due to the software changes.

1. ESP32 reads the K type thermocouple via MAX31855 as before.

2. Temperature reading is now stored in a mySQL database ever minute

3. A webpage pulls this temperature data from mySQL server and uses Google Charts to display the historical information in graph form. With the addition of the current value in numerical form.

4. As the data is now in mySQL I can also use other systems to display the data such as Grafana.

Google charts graphing of temperature data.



*******                        CURRENT ESP32 CODE BELOW                             ********

 // Target device isWEMOS LOLIN 32
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include <WiFi.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MAX31855.h>
#define MAXDO   26
#define MAXCS   16
#define MAXCLK  25

Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);
int tempC=0; // Intialize a variable for temperature in celcius
int tempF=0; // Intialize a variable for temperature in farenhiet

// Create the temperature object, defining the pins used for communication
//MAX31855 temp(MISO, CS, SCK);  
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
/*
   CREATE TABLE test_arduino.meat (
    num integer primary key auto_increment,
    temp integer,
    recorded timestamp
  );
*/

// MySQL server listening address changed to any and worked as expected after changing user to insert user

const char* ssid = "ssid";
const char* password = "password";
char user[] = "username"; // MySQL user login username
char passwordSQL[] = "password"; // MySQL user login password

char query[128];
IPAddress server_addr(192,168,0,127); // IP of the MySQL server here

WiFiServer  server(80);
 
void setup() {
  Serial.begin(115200); 
  // Start I2C Communication SDA = 5 and SCL = 4 on Wemos Lolin32 ESP32 with built-in SSD1306 OLED
  Wire.begin(5, 4);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000); // Pause for 2 seconds
 // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  // Clear the buffer.
  display.clearDisplay();
  connectToNetwork();
}
 
void loop() {
   delay(9000); // need to change to non blocking delay
   delay(9000);
  Serial.print("Junction=");
  Serial.println(thermocouple.readInternal());  // get junction temp from MAX318555 i.e. ambient
  Serial.print("Thermocouple=");
  Serial.println(thermocouple.readCelsius()); // get temp from k-type thermocouple probe attached to MAX318555
 // tempF =(thermocouple.readFarenheit());
  tempC =(thermocouple.readCelsius());
  // changed so we save result after reading temp
  mySqlLoop();
  display_temp();
}
void connectToNetwork() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    wifi_connecting();
    Serial.println("Establishing connection to WiFi..");
  }
  wifi_connected();
  Serial.println("Connected to network");
}
void mySqlLoop(){
 char INSERT_SQL[] = "INSERT INTO test_arduino.meat (temp) VALUES (%d)";
  WiFiClient client;
  MySQL_Connection conn((Client *)&client);
  if (conn.connect(server_addr, 3306, user, passwordSQL)) {
    Serial.println("Database connected.");
    data_connected();
  }
  else{
    Serial.println("Connection failed.");
    Serial.println("Recording data.");
    data_failed();
  }
  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  sprintf(query, INSERT_SQL,  tempC);
  // Execute the query
  cur_mem->execute(query);
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used
  delete cur_mem;
  Serial.println("closing connection\n");
  data_updated();
  //client.stop();
}

void display_temp(void) {
//display_setup(); 
  display.clearDisplay();
  display.setTextSize(3);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 8);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font
  display.print(tempC);
  display.print(" oC");
  display.display();
  delay(2000);
 display.clearDisplay();
}
void data_connected(void) {
display_setup();
  display.println(F("    DATA"));  
  display.println(F(" CONNECTED"));
  display.display();
  delay(2000);
 display.clearDisplay();
}
void data_failed(void) {
 display_setup();
  display.println(F("    DATA"));  
  display.println(F("   FAILED "));
  display.display();
  delay(2000);
 display.clearDisplay();
}
void data_updated(void) {
  display_setup(); 
  //  display.write(' ');
  display.println(F("    DATA"));  
  display.println(F("  UPDATED "));
  display.display();
  delay(2000);
 display.clearDisplay();
   delay(2000);
}
void wifi_connected(void) {
  display_setup();
  //  display.write(' ');
  display.println(F("    WIFI"));  
  display.println(F(" CONNECTED"));
  display.display();
  delay(2000);
 display.clearDisplay();
}
void wifi_connecting(void) {
 display_setup();
  //  display.write(' ');
  display.println(F("   WIFI"));  
  display.println(F("CONNECTING"));
  display.display();
  delay(2000);
 display.clearDisplay();
}
void display_setup(void) {
  display.clearDisplay();
  display.setTextSize(2);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font
}

*******                        CURRENT MEAT.PHP CODE BELOW                            ********
<?php
 $con = mysqli_connect('ip','user_name','password','mySQL_Table');
?>
<!DOCTYPE HTML>
<html>
<head>
 <meta charset="utf-8">
 
 <title>Meat Probe</title>
 
 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
 <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
 <script type="text/javascript" src="https://www.google.com/jsapi"></script>
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
 <script type="text/javascript">
 
 google.load("visualization", "1", {packages:["corechart"]});
 google.setOnLoadCallback(drawChart);
 function drawChart() {
 var data = google.visualization.arrayToDataTable([
 
 ['temp','recorded'],
 <?php
 $query = "SELECT * FROM `meat` WHERE DATE(recorded) = DATE(NOW())";
 $exec = mysqli_query($con,$query);
 while($row = mysqli_fetch_array($exec)){
 echo "['".$row['recorded']."',".$row['temp']."],";
 }
 ?>
 ]);
 var options = {
 title: 'Meat Temp',
 curveType: 'function',                // add curve to chart to smooth out transitions

  pieHole: 0.5,
          pieSliceTextStyle: {
            color: 'black',
          },
          legend: 'none'
 };
 var chart = new google.visualization.LineChart(document.getElementById("columnchart12"));
 chart.draw(data,options);  //try material line charts as newer and better apparently
 }
    </script>
 
</head>
<body>
 <div class="alert alert-primary" role="alert">
 <?php
$sql ="SELECT * FROM meat
WHERE num IN (SELECT num FROM meat WHERE recorded = (SELECT MAX(recorded) FROM meat))
ORDER BY num DESC
LIMIT 1";
 
$result = $con->query($sql);

if ($result->num_rows > 0) {
  // output data of each row - doh only one row
  while($row = $result->fetch_assoc()) {
    echo  "  Probe Temp: " . $row["temp"]. "oC<br>";
  }
} else {
  echo "0 results";
}
?>
</div>
 <div class="container-fluid">
 <div id="columnchart12" style="width: 100%; height: 300px;"></div>
 </div>

 <div class="alert alert-primary" role="alert">
 <h2><b>Cooking Temperatures</b></h2>
 <p></p><p></p>
             <table>
             <tr>
             <th></th>
             <td><b>&nbsp;&nbsp;&nbsp;74oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Chicken, Turkey &amp; Duck&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;140oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 1 </td>
             </tr>
             <tr>
             <td>Rare</td>  
             <td><b>&nbsp;&nbsp;&nbsp;52oC&nbsp;&nbsp;&nbsp;</b></td>
             <td>  Beef, Lamb &amp; Veal&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;150oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 2 </td>
             </tr>
             <tr>
             <td>Medium</td>
             <td><b>&nbsp;&nbsp;&nbsp;60oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Beef, Lamb &amp; Veal&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;170oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 3</td>
             </tr>
             <tr>
             <td>Well Done  </td>
             <td><b>&nbsp;&nbsp;&nbsp;71oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Beef, Lamb &amp; Veal&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;180oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 4</td>
             </tr>
             <tr>
             <td>Medium</td>
             <td><b>&nbsp;&nbsp;&nbsp;63oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Pork Roasts, Steaks &amp; Chops&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;190oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 5</td>
             </tr>
             <tr>
             <td>Well Done  </td>
             <td><b>&nbsp;&nbsp;&nbsp;71oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Pork Roasts, Steaks &amp; Chops&nbsp;&nbsp;&nbsp;</td>  <td><b>&nbsp;&nbsp;&nbsp;200oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 6 </td>
             </tr>
             <tr>
             <td></td>
             <td><b>&nbsp;&nbsp;&nbsp;60oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Fish&nbsp;&nbsp;&nbsp;</td> <td><b>&nbsp;&nbsp;&nbsp;220oC &nbsp;&nbsp;&nbsp;</b></td><td>  Gas Mark 7</td>
             </tr>
              <tr>
             <td></td>
             <td>  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
             <td>  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;230oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Gas Mark 8</td>
             </tr>
              <tr>
             <td></td>
             <td>  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
             <td>  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td><b>&nbsp;&nbsp;&nbsp;240oC &nbsp;&nbsp;&nbsp;</b></td>
             <td>  Gas Mark 9</td>
             </tr>
             </table>
</div>
</body>
</html>



use at own risk software still needs a few tweaks will post update when its all done.

The grafana graph below is from a cook of a brisket in the wood fired oven.







Comments