WLAN Grillthermometer

Über den Beitrag

In meinem letzten Beitrag hatte ich gezeigt, wie ihr ein 433 MHz Funk Grillthermometer mit grafischer Anzeige des Temperaturverlaufs bauen könnt. Der Bastelaufwand war recht erheblich, was einige von einem Nachbau abhalten könnte. Deshalb möchte ich in diesem Beitrag eine erheblich einfachere Variante auf WLAN Basis vorstellen. Hier müsst ihr nur eine Sendeeinheit bauen, denn als Empfänger dient der Browser eures Smartphones, Tablets, PCs oder Laptops. Auch die Sendeeinheit selbst ist einfacher gehalten, indem ich bei ihr auf ein Display und den externen A/D-Wandler verzichte. Und da ich einen ESP32 als Mikrocontroller verwende, wird auch kein Funkmodul benötigt.

Der Nachteil ist, dass die Grafik mit dem Temperaturverlauf fehlt. Hingegen müsst ihr auf eine Warnung bei Erreichen der Zieltemperatur nicht verzichten. Das realisiere ich über den IFTTT Dienst (if-this-then-that), da eine direkte akustische Warnung über den Browser nur über einige Umwege möglich wäre.

Das Konzept

Hier zunächst die Schaltung:

WLAN Grillthermometer - die Schaltung
WLAN Grillthermometer – die Schaltung

Der Temperaturfühler wird dabei durch seine Anschlussbuchse repräsentiert.

Und so sah es auf dem Breadboard aus:

WLAN Grillthermometer - Versuchsaufbau auf dem Breadboard
WLAN Grillthermometer – Versuchsaufbau auf dem Breadboard

Ich benutze übrigens eine LED mit integriertem Vorwiderstand – bevor jemand fragt, warum hier ein Widerstand fehlt.

Temperaturmessung

Wie im letzten Beitrag verwende ich auch hier einen Ersatzfühler für Grillthermometer, den es bei Amazon und anderen Online-Shops für ein paar Euro gibt. Der Temperaturfühler ändert seinen Widerstand mit der Temperatur. Entsprechend ändert sich die über ihn abfallende Spannung, wenn ihr ihn in einem Spannungsteiler einsetzt. Gegenüber dem zuletzt vorgestellten Grillthermometer vereinfache diesen Teil der Schaltung dahin gehend, dass ich nur die Thermometerspannung und nicht die 3.3 Volt Gesamtspannung messe. Dafür ist eine sehr stabile Gesamtspannung erforderlich.

Der A/D-Wandler des ESP32 ist nicht wirklich linear (Details hier) und liefert recht viel Rauschen. Letzteres lässt sich etwas durch Kondensatoren mindern, wie vom Hersteller Espressif empfohlen (siehe hier). Die Nicht-Linearität wird einfach „wegkalibriert“.

Stromversorgung für das WLAN Grillthermometer

Wie ein ESP32 Board am besten mit Batterien oder Akkus betrieben wird, darüber scheiden sich die Geister. Wenn ihr euer Board am PC programmiert, bekommt es seine Versorgungsspannung über die USB Buchse, also 5 Volt. Meistens befindet sich auf dem Board ein AMS1117-3.3 Spannungsregler, der die Versorgungsspannung auf die für den ESP32 benötigten 3.3 Volt reduziert. Der AMS1117-3.3 verträgt laut Datenblatt Spannungen, die bis zu 12 Volt über der Ausgangsspannung liegen dürfen.

Der Pin „V5“ (er mag bei eurem Board etwas anders heißen) ist direkt mit dem Stromanschluss der USB Buchse verbunden und wird normalerweise genutzt, um dort die 5 Volt abzugreifen. Meiner Meinung nach spricht nichts dagegen, diesen als Eingang für die Spannungsversorgung zu nutzen und dabei über die 5 Volt hinauszugehen. Da in einem Spannungsregler Ein- und Ausgangsstrom identisch sind (siehe auch hier) und die Spannung sich ändert, wird die Leistung P=ΔU⋅I in Form von Wärme abgegeben. Aber auch nach längerem Betrieb ist das Teil in meinem Projekt nicht sonderlich warm geworden.

ESP32 Board mit AMS1117 Spannungsregler
ESP32 Board mit AMS1117 Spannungsregler

Auswahl des Akkutyps

Als Spannungsversorgung verwende ich einen Lithium-Ionen-Akku. Genau genommen verwende ich zwei hintereinandergeschaltete 3.7 V Akkus. Genauso gut könnt ihr einen 9V Lithium-Akku verwenden. Intern besteht dieser auch aus zwei Lithium-Ionen-Akkus und liefert deswegen übrigens keine 9 Volt, auch wenn die Bezeichnung es suggeriert. Frisch aufgeladen liefern sie ca. 8.4 Volt.

Mit dieser Stromversorgung habe ich eine sehr stabile Spannung am 3.3 Volt Pin erhalten. Die Schwankung lag deutlich unter einem hundertstel Volt, selbst wenn die Akkuladung auf unter 7 Volt fiel. Ab da schreitet die Entladung recht schnell voran und der Akku sollte getauscht werden.

Weitere Verbraucher solltet ihr nicht an den 3.3 Volt Ausgang hängen – oder ihr verwendet doch lieber die Messmethode aus dem letzten Beitrag, bei der ich die Gesamtspannung am 3.3 Volt Ausgang mit gemessen habe.

Die Diode am 5 V Pin dient dem Schutz vor Verpolung. Das ist optional.

Wichtiger Hinweise zum Akkubetrieb – bitte lesen!

Da Pin V5 direkt mit der USB Buchse verbunden ist, dürft ihr auf gar keinen Fall einen Akku verwenden, während das Board am Computer hängt!

Messung der Akkuspannung

Es ist sinnvoll, die Akkuspannung zu überwachen, damit das Thermometer nicht im falschen Moment ausfällt. Da die Akkuspannung zu hoch für den A/D-Wandler des ESP32 ist, messe ich sie indirekt über einen Spannungsteiler. Hier muss allerdings der Fehler des ESP32 A/D-Wandlers berücksichtigt werden. Wenn man den Spannungsteiler aber geschickt dimensioniert, landet man in einem Bereich, in dem der A/D-Wandler linear arbeitet und in erster Näherung um einen festen Offset verschoben ist (siehe rechts). Die Werte könnt ihr dann recht einfach korrigieren. Ich habe einfach verschiedene bekannte Spannungen zwischen 6.5 und 8.5 Volt an den Spannungsteiler angelegt und die geteilte Spannung mit dem A/D-Wandler ausgelesen.

U_{\text{geteilt, ideal}}\;[\text{V}]=\frac{\text{analogRead}(34)}{4095}\cdot 3.3

Die reale geteilte Spannung war um ca. 0.14 Volt höher. Das habe ich mit einem verlässlichen Multimeter gemessen. Die Umrechnung in die Versorgungsspannung erfolgt dann über einen festen Faktor, der durch das Verhältnis der Widerstände bestimmt ist:

U_{\text{Versorgung}}\;[\text{V}]=\left(U_{\text{geteilt, ideal}}+0.14\right)\cdot3.237

Power-On LED

Die LED an GPIO17 hat einfach nur den Sinn euch anzuzeigen, dass das Thermometer angeschaltet ist. Ihr könntet sonst leicht vergessen, es nach Gebrauch auszuschalten. Das ist natürlich auch optional.

Kalibrierung

Für die Aufnahme der Kalibrierkurve habe ich, wie für das letzte Thermometer, einen Topf mit Wasser erhitzt und beim Abkühlen Temperatur-/Spannungswerte mithilfe eines Referenzthermometers meines Vertrauens aufgenommen. Für die Spannungswerte habe ich 50 Einzelwerte gemittelt.

void setup(){
  Serial.begin(115200);
}

void loop(){
  unsigned long sum = 0;
  unsigned int numberOfSamples = 50;

  for(int i=0; i<numberOfSamples; i++){
    sum += analogRead(33);
  }
  
  float milliVolts = (sum /(numberOfSamples*1.0))/4.095 * 3.3;
  Serial.println(milliVolts);
  delay(500);
}

 

In Excel habe ich dann ein Ausgleichspolynom („Trendlinie“) durch die Messwerte gelegt. Erst ein Polynom vierter Ordnung passte.

WLAN Grillthermometer - Kalibrierkurve
Kalibrierkurve 0 – 100 °C

Auch wenn es so funktioniert hätte, habe ich mich am Ende dafür entschieden, die Kurve zu stückeln und kleinere Polynome zu verwenden:

Kalibrierung WLAN Grillthermometer 0-45 Grad
0 – 45 °C
Kalibrierung WLAN Grillthermometer 45-70 Grad
45 – 70 °C
Kalibrierung WLAN Grillthermometer 70-100 Grad
70 -100 °C

Wie ihr dafür sorgt, dass die Koeffizienten eures Polynoms mit genügend Dezimalstellen ausgegeben werden, habe ich im letzten Beitrag beschrieben.

Der Sketch für das WLAN Grillthermometer

Option 1: Die einfache Lösung

Die einfache Lösung zeigt euch lediglich die Temperatur und die Akkuspannung in einem beliebigen Browser an, beispielsweise auf eurem Smartphone oder Tablet. Die Grundlagen der WLAN Nutzung habe ich hier im Detail behandelt. In diesem Beitrag gehe ich nur grob darauf ein. Hier zunächst der Sketch.

#include <WiFi.h>
#include <WebServer.h>
#define TEMPERATURE_PIN 33
#define SUPPLY_VOLTAGE_PIN 34
#define LED_PIN 17   // power-on LED

const char* ssid = "Your WiFi name";
const char* pass = "Your WiFi password"; 

WebServer server(80);  // creating a webserver object
 
String headString = "<head><style>" // head and CSS style elements
                      ".blueBox {"
                        "background-color: blue;"
                        "color: white;"
                        "width: 600px;" 
                        "padding: 20px;"
                        "text-align: center;"
                        "font-size: 50px;"
                        "font-family: arial;"
                        "margin: 20px 35px;"
                      "}"
                    "</style>";
                      
String refreshString = "<meta http-equiv=\"refresh\" content=\"10\"></head>";                      
String trackTempString = "</BR><h1 align=\"center\">BBQ - Current Temperature</h1></div>";

void setup(){
  pinMode(LED_PIN, OUTPUT); 
  digitalWrite(LED_PIN, HIGH);
  Serial.begin(115200);
  Serial.println("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());
  
  server.on("/",trackTemperatureScreen);
  server.begin();
}
  
void loop(){
  server.handleClient(); 
}

void trackTemperatureScreen(){
  String message = "";
  float bbqTemp = getBbqTemperature();
  float supplyVoltage = getSupplyVoltage();
   
  message += headString;
  message += refreshString;
  message += trackTempString;
  message += "<div align=\"center\";>";
  message += "<div class=\"blueBox\">";
  message += "Current Temperature [&ring;C]: </BR></BR><span style=\"font-size: 100px;\">";
  message += String(bbqTemp, 1);
  message += "</span>";
  message += "</div>";
  message += "</BR><h2>Supply Voltage [V]: ";
  message += String(supplyVoltage,1);
  message += "</h2></div>";
  
  server.send(200, "text/html", message);
}

float getBbqTemperature(){
  // replace by your calibration function(s)
  // 70-100°C: y = 28.436x2 - 89.635x + 128.71
  // 45-70°C:  y = 6.3363x2 - 50.673x + 111.64
  // 0-45°C:   y = -2.3284x2 - 23.46x + 90.312
  
  float tV = 0.0; // thermometer voltage
  float tC = 0.0; // temperature Celsius
  unsigned long tempSum = 0;
  unsigned int numberOfSamples = 50;

  for(int i=0; i<numberOfSamples; i++){
    tempSum += analogRead(TEMPERATURE_PIN);
  }
  tV = (tempSum /(numberOfSamples*1.0))/4095.0 * 3.3;
  
  if(tV < 1.0){
    tC = 28.436*pow(tV,2) - 89.635*tV + 128.71; 
  }
  else if(tV < 1.7){
    tC = 6.3363*pow(tV,2) - 50.673*tV + 111.64; 
  }
  else{
    tC = -2.3284*pow(tV,2) - 23.46*tV + 90.312; 
  }
  return tC;
}

float getSupplyVoltage(){
  unsigned long sum = 0;
  unsigned int numberOfSamples = 50;
  for(int i=0; i<numberOfSamples; i++){
    sum += analogRead(SUPPLY_VOLTAGE_PIN);
  }
  float volts = (sum /(numberOfSamples*1.0))/4095.0 * 3.3;
  volts = (volts + 0.14) * 3.237;
  return volts;
}

 

Erläuterungen zum Sketch

Der ESP32 dient als Server, der die Temperatur und die Akkuspannung auf einer Website darstellt. Der Inhalt der Website wird als String („message“) an den Client, also den Browser, übertragen. Die Einbettung von HTML Code in Arduino Code ist für die Lesbarkeit nicht förderlich, aber das liegt in der Natur der Sache. Noch ein paar Erklärungen:

  • „ssid“ / „pass“ sind die Zugangsdaten für euer WLAN
  • In „headString“ wird das Gestaltungselement „blaue Box“ als CSS-Code definiert. 
  • Der Inhalt von „refreshString“ sorgt für eine Aktualisierung der Website im Abstand von 10 Sekunden.
  • Der serielle Monitor zeigt die IP an, die euer Router dem ESP32 zuweist. Am besten stellt ihr in eurem Router ein, dass der ESP32 immer diese IP bekommt.
  • server.on("/",trackTemperatureScreen); bewirkt, dass bei Aufruf der IP-Adresse (es gibt nur den Hauptpfad „/“) die Funktion trackTemperatureScreen() aufgerufen wird.
  • trackTemperatureScreen() initiiert neue Messungen, stellt den Inhalt der Website zusammen und sendet ihn an den Server. 

Ausgabe der Option 1

WLAN Grillthermometer - Ausgabe der einfachen Lösung auf dem Smartphone

Geht in den Browser des Gerätes eurer Wahl und gebt dort die IP eures ESP32 ein. Bei mir ist das „192.168.178.38“. Eventuell müsst ihr auch noch einen Schrägstrich anhängen, also „192.168.178.38/“. Alle 10 Sekunden sollte ein aktualisierter Wert erscheinen.

Wenn ihr Probleme habt, dann hängt den ESP32 direkt an euren Computer und schaut, ob sich der ESP32 mit dem Heimnetz verbindet und ob die IP-Adresse stimmt.

Option 2: Die „Komfort-Lösung“

Die Komfort-Lösung für das WLAN Grillthermometer umfasst die Einstellung eines Temperaturlimits und eine Warnung, wenn das Limit erreicht wurde. Das klingt eigentlich nach einer geringfügigen Ergänzung, aber der resultierende Sketch war am Ende zweieinhalb mal so lang.

Einstellung der Zieltemperatur

WLAN Grillthermometer - setTemperatureScreen

Für die Einstellung der Zieltemperatur gibt es einen eigenen Bildschirm (siehe rechts). Er erscheint, wenn die Website aufgerufen wird. Im Sketch geschieht das durch den Aufruf von setTemperatureScreen(). Die Voreinstellung für die Zieltemperatur ist 55 °C. Durch Tippen auf die Felder +/- 10 °C und +/- 1 °C könnt ihr die Zieltemperatur verändern. Diese Felder sind als HTML Buttons definiert und mit entsprechenden Pfaden der Website verlinkt. Dafür musste ich den Sketch um eine Reihe weiterer server.on() Funktionen erweitern. Die server.on() Funktionen rufen wiederum Funktionen auf, die die Zieltemperatur wie angefordert ändern.

Ich habe die Einstellung so programmiert, dass die Zieltemperatur zwischen 40 und 99 °C gewählt werden kann. Das könnt ihr natürlich ändern, wenn es euch sinnvoll erscheint.

Habt ihr die gewünschte Zieltemperatur eingestellt, tippt ihr auf „Accept Target“ und landet dann auf dem „trackTemperatureScreen“ (siehe nächstes Bild).

Verfolgen der Temperatur

Der „trackTemperatureScreen“ für das WLAN Grillthermometer zeigt die aktuelle Temperatur und die Akkuspannung an. Zu Beginn wird die Temperatur in weißer Schrift angezeigt. Bei fünf Grad unter Zieltemperatur wird sie orange. Ab einem Grad unter Zieltemperatur wird sie rot.

Zusätzlich hat der Bildschirm zwei „Buttons“. Der eine heißt „New Target“ und führt zurück zur Zieltemperatureinstellung. Mit dem zweiten Button könnt ihr den Alarm aus- und auch wieder anstellen. Er wechselt dann entsprechend Farbe und Beschriftung. Wenn der Alarm ausgelöst wurde, wird er deaktiviert.

WLAN Grillthermometer - trackTemperatureScreen
Der „trackTemperatureScreen“ bei verschiedenen Temperaturen

Alarm auslösen mit IFTTT

Aus Sicherheitsgründen ist es Websites nicht direkt möglich, Programme auf eurem Gerät aufzurufen, euer Smartphone zum Klingeln zu bringen oder ähnliche Aktionen zu initiieren, die ihr als Alarm nutzen könntet. Selbst das automatische Abspielen von Audiodateien ist nur über Umwege und Sondereinstellungen möglich.

Um trotzdem einen Alarm auszulösen, nutze ich den kostenlosen Dienst IFTTT (if-this-then-that). Was das genau ist, wie ihr den Zugang einrichtet und mit dem Dienst umgeht habe ich hier beschrieben. Ich werde die Erklärungen in diesem Beitrag deswegen kurz halten.

Benachrichtigung vom WLAN Grillthermometer per IFTTT

Auf IFTTT kreiert ihr in wenigen Minuten sogenannte Applets, die aus einem Auslöser („if this“) und einer Aktion („then that“) bestehen. Der Auslöser ist in diesem Fall ein sogenannter „Webhook“. Das ist eine kleine Nachricht in einem bestimmten Format, die von Websites per POST- oder GET-Request an IFTTT geschickt werden. Diese Aufgabe übernimmt in meinem Sketch die Funktion send_webhook(). Ihr braucht euch also nicht um die Details zu kümmern. Mit dem Webhook könnt ihr bis zu drei Variablen übermitteln, also in diesem Fall die Temperatur eures WLAN Grillthermometers.

Die Aktion, die das Senden des Webhooks auslösen soll, ist eine Benachrichtigung (notification) auf euer Smartphone (siehe oben rechts). Den Text könnt ihr frei variieren. Wie ihr das konkret macht, habe ich in dem schon erwähnten Artikel an dieser Stelle beschrieben. Es ist wirklich einfach.

Einschränkungen

Es gibt da noch zwei kleine Problemchen:

  1. Wenn sich euer Telefon nach einigen Minuten ohne Benutzung „schlafen legt“, kommen die Benachrichtigungen verzögert.
  2. Das Update der Temperatur und die Überprüfung des Temperaturlimits wird durch eine Anfrage des Browsers ausgelöst. Schläft euer Smartphone, gibt es kein Update und keinen Alarm.

Zur Lösung von Problem 1 empfehle ich, die Zeit bis zur Aktivierung der Bildschirmsperre hochzusetzen. Das lässt sich in den Einstellungen ändern, ist aber auf Dauer nervend. Mit Apps lässt sich das bequemer realisieren. Screen Alive funktioniert beispielsweise wunderbar für Android Smartphones. Die kostenlose und werbefreie App bietet ein Widget mit dem ihr den „Immer an“ Modus mit einem einzigen Klick aktivieren könnt. Alternativ verwendet ihr nicht die Benachrichtigungen, sondern SMS als „then that“. Der Nachteil ist, dass der Dienst auf 10 SMS pro Monat begrenzt ist.

Das zweite Problem habe ich gelöst, indem ich die Temperatur zusätzlich in loop() abfrage. Das passiert aber nur, wenn mindestens 15 Sekunden seit der letzten Temperaturabfrage vergangen sind.  

Der Sketch für die Komfort Lösung

Hier nun der vollständige Sketch für das WLAN Grillthermometer:

#include <WiFi.h>
#include <WebServer.h>
#define TEMPERATURE_PIN 33
#define SUPPLY_VOLTAGE_PIN 34
#define LED_PIN 17   // power-on LED

#define IFTTT_Key "Your IFTTT Key"
#define IFTTT_Event "BBQ_Event"
#define IFTTT_Value1 "Hi! "
#define IFTTT_Value3 "dummy";

const char* ssid = "Your WiFi SSID";
const char* pass = "Your WiFi Password";
unsigned int bbqTargetTemp = 55;
unsigned long lastTempMeasurement = 0;
volatile bool tempAlert = true;

WebServer server(80);
 
String headString = "<head><style>" // head and CSS style elements
                      ".button {"
                        "border: none;"
                        "color: white;"
                        "width: 350px;"
                        "padding: 20px;"
                        "text-align: center;"
                        "margin: 20px 35px;"
                      "}"
                      ".greenButton {background-color: green; font-size: 64px;}"
                      ".greenButton:hover {background-color: darkgreen; font-size: 64px;}"
                      ".redButton {background-color: red; font-size: 64px;}"
                      ".redButton:hover {background-color: darkred; font-size: 64px;}"
                      ".blueButton {background-color: blue; font-size: 50px;}"
                      ".blueButton:hover {background-color: darkblue; font-size: 50px;}"
                      ".blueBox {"
                        "background-color: blue;"
                        "color: white;"
                        "width: 600px;" 
                        "padding: 20px;"
                        "text-align: center;"
                        "font-size: 50px;"
                        "font-family: arial;"
                        "margin: 20px 35px;"
                      "}"
                    "</style>";
                      
String refreshString = "<meta http-equiv=\"refresh\" content=\"10\"></head>";                      
String setTargetString = "</BR><h1 align=\"center\">BBQ - Set your Target Temperature</h1></div>";
String trackTempString = "</BR><h1 align=\"center\">BBQ - Current Temperature</h1></div>";
String plus10String = "<a href=\"/plus_10\"><button class=\"button greenButton\">+ 10&ring;C</button></a>";
String minus10String = "<a href=\"/minus_10\"><button class=\"button redButton\">- 10&ring;C</button></a>";
String plus1String = "</BR><a href=\"/plus_1\"><button class=\"button greenButton\">+ 1&ring;C</button></a>";
String minus1String = "<a href=\"/minus_1\"><button class=\"button redButton\">- 1&ring;C</button></a>";
String setNewTargetString = "</BR><a href=\"/\"><button class=\"button greenButton\">New Target</button></a>";
String enableAlertString = "</BR><a href=\"/enableAlert\"><button class=\"button greenButton\">Enable Alert</button></a>";
String disableAlertString = "</BR><a href=\"/disableAlert\"><button class=\"button redButton\">Disable Alert</button></a>";

void setup(){
  pinMode(LED_PIN, OUTPUT); 
  digitalWrite(LED_PIN, HIGH);
  Serial.begin(115200);
  Serial.println("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());
  
  server.on("/",handleRoot);
  server.on("/plus_10", plus10);
  server.on("/minus_10", minus10);
  server.on("/plus_1", plus1);
  server.on("/minus_1", minus1);
  server.on("/enableAlert", enableAlert);
  server.on("/acceptTemp", trackTemperatureScreen);
  server.on("/disableAlert", disableAlert);
  server.on("/trackTemperature", trackTemperatureScreen);
  server.begin();
}
  
void loop(){
  server.handleClient();
  if(((lastTempMeasurement - millis()) > 15000) && tempAlert){
    float bbqTemp = getBbqTemperature();
    alertCheck(bbqTemp);
  }
}

void handleRoot() {
  setTemperatureScreen();
}

void plus10(){
  bbqTargetTemp += 10;
  setTemperatureScreen();
}

void minus10(){
  bbqTargetTemp -= 10;
  setTemperatureScreen();
}

void plus1(){
  bbqTargetTemp++;
  setTemperatureScreen();
}

void minus1(){
  bbqTargetTemp--;
  setTemperatureScreen();
}

void acceptTemp(){
  enableAlert();
}

void enableAlert(){
  tempAlert = true;
  trackTemperatureScreen();
}

void disableAlert(){
  tempAlert = false;
  trackTemperatureScreen();
}

void trackTemperatureScreen(){
  String message = "";
  float bbqTemp = getBbqTemperature();
  float supplyVoltage = getSupplyVoltage(); 
  String colorString = "white";

  if((bbqTargetTemp - bbqTemp) < 1.0){
    colorString = "red";
  }
  else if((bbqTargetTemp - bbqTemp) < 5.0){
    colorString = "orange";
  }
  
  message += headString;
  message += refreshString;
  message += trackTempString;
  message += "<div align=\"center\";>";
  message += "<div class=\"blueBox\">";
  message += "Current Temperature [&ring;C]: </BR></BR><span style=\"font-size: 100px; color: ";
  message += (colorString + "\">");
  message += String(bbqTemp, 1);
  message += "</span>";
  message += "</BR></BR>Target [&ring;C]: ";
  message += String(bbqTargetTemp);
  message += "</div>";
  message += setNewTargetString;

  if(tempAlert){
    message += disableAlertString;
  }
  else{
    message += enableAlertString;
  }
  message += "</BR><h2>Supply Voltage [V]: ";
  message += String(supplyVoltage,1);
  message += "</h2></div>";
  
  server.send(200, "text/html", message);

  alertCheck(bbqTemp);  
}

float getBbqTemperature(){
  // replace by your calibration function(s)
  // 70-100°C: y = 28.436x2 - 89.635x + 128.71
  // 45-70°C:  y = 6.3363x2 - 50.673x + 111.64
  // 0-45°C:   y = -2.3284x2 - 23.46x + 90.312
  
  float tV = 0.0; // thermometer Voltage
  float tC = 0.0; // temperature Celsius
  unsigned long tempSum = 0;
  unsigned int numberOfSamples = 50;

  for(int i=0; i<numberOfSamples; i++){
    tempSum += analogRead(TEMPERATURE_PIN);
  }
  tV = (tempSum /(numberOfSamples*1.0))/4095.0 * 3.3;
  
  if(tV < 1.0){
    tC = 28.436*pow(tV,2) - 89.635*tV + 128.71; 
  }
  else if(tV < 1.7){
    tC = 6.3363*pow(tV,2) - 50.673*tV + 111.64; 
  }
  else{
    tC = -2.3284*pow(tV,2) - 23.46*tV + 90.312; 
  }
  lastTempMeasurement = millis();
  return tC;
}

float getSupplyVoltage(){
  unsigned long sum = 0;
  unsigned int numberOfSamples = 50;
  for(int i=0; i<numberOfSamples; i++){
    sum += analogRead(SUPPLY_VOLTAGE_PIN);
  }
  float volts = (sum /(numberOfSamples*1.0))/4095.0 * 3.3;
  volts = (volts + 0.14) * 3.237;
  return volts;
}

void alertCheck(float currentTemp){
  String tString = String(currentTemp, 1); // convert temperature as float into String
  if((currentTemp > bbqTargetTemp) && tempAlert){
    send_webhook(tString);
    tempAlert = false; 
  }
}

void setTemperatureScreen(){
  String message = "";
  
  if(bbqTargetTemp >= 100){
    bbqTargetTemp -= 60;
  }
   if(bbqTargetTemp < 40){
    bbqTargetTemp += 60;
  }
  
  message += headString;
  message += setTargetString;
  message += "<div align=\"center\";>";
  message = message + plus10String + minus10String + plus1String + minus1String;
  message += "</BR><a href=\"/acceptTemp\"><button class=\"button blueButton\">";
  message += "Accept</BR>Target [&ring;C]: </BR>";
  message += String(bbqTargetTemp);
  message += "</button></a>";
  message += "</div>";
  server.send(200, "text/html", message); 
}

void send_webhook(String IFTTT_Value2){
  WiFiClient client;
  // construct the JSON payload
  String jsonString = "";
  jsonString += "{\"value1\":\"";
  jsonString += IFTTT_Value1;
  jsonString += "\",\"value2\":\"";
  jsonString += IFTTT_Value2;
  jsonString += "\",\"value3\":\"";
  jsonString += IFTTT_Value3;
  jsonString += "\"}";
  int jsonLength = jsonString.length();  
  String lenString = String(jsonLength);

  // connect to the Maker event server
  client.connect("maker.ifttt.com", 80);

  // construct the POST request
  String postString = "";
  postString += "POST /trigger/";
  postString += IFTTT_Event;
  postString += "/with/key/";
  postString += IFTTT_Key;
  postString += " HTTP/1.1\r\n";
  postString += "Host: maker.ifttt.com\r\n";
  postString += "Content-Type: application/json\r\n";
  postString += "Content-Length: ";
  postString += lenString + "\r\n";
  postString += "\r\n";
  postString += jsonString; // combine post request and JSON
  
  client.print(postString);
  delay(500);
  client.stop();
}

 

Der Sketch ist aufgrund seiner Länge und der Durchmischung von HTML, CSS, und Arduino Code etwas schwer zu verdauen. Der HTML und CSS Code wird stückweise zusammengesetzt. Alle Anführungsstriche, die nicht Teil des Arduino Codes sind, müssen mit einem vorangestellten Backslash versehen werden, was auch nicht gerade zur besseren Lesbarkeit beiträgt. Wenn ihr hinsichtlich der Website selbst gestalterisch tätig werden wollt, dann empfehle ich, das erst einmal separat mit einem guten Editor wie Notepad++ zu tun. Für alle Variablen setzt ihr Dummies ein. So sieht beispielsweise der reine HTML-/CSS-Code für den „trackTemperatureScreen“ aus:

<head>
  <style>
    .button {
      border: none;
      color: white;
      width: 350px;
      padding: 20px;
      text-align: center;
      margin: 20px 35px;
    }
    .greenButton {background-color: green; font-size: 64px;}
    .greenButton:hover {background-color: darkgreen; font-size: 64px;}
    .redButton {background-color: red; font-size: 64px;}
    .redButton:hover {background-color: darkred; font-size: 64px;}
    .blueButton {background-color: blue; font-size: 50px;}
    .blueButton:hover {background-color: darkblue; font-size: 50px;}
    .blueBox {
      background-color: blue;
      color: white;
      width: 600px; 
      padding: 20px;
      text-align: center;
      font-size: 50px;
      font-family: arial;
      margin: 20px 35px;
    }
  </style>
    <meta http-equiv="refresh" content="10">
</head> 
</BR>
<h1 align="center">BBQ - Current Temperature</h1>
<div align="center">
  <div class="blueBox">
        Current Temperature [&ring;C]: </BR></BR>
    <span style="font-size: 100px; color: red">
      99.9
    </span>
    </BR></BR>
    Target [&ring;C]: 99.9
  </div>
  </BR>
  <a href="/"><button class="button greenButton">New Target</button></a>
  </BR>
  <a href="/disableAlert"><button class="button redButton">Disable Alert</button></a>
  </BR>
  <h2>Supply Voltage [V]: 9.9</h2>
</div>

 

Zusammenbau

Ich habe ein einfaches Universal-Elektronikgehäuse verwendet, das nicht viel größer als das ESP32 Board ist. Die Platine habe ich aus einer Lochrasterplatine ausgesägt. Die Platine ist mit Abstandshaltern auf der Bodenplatte befestigt. Das Batteriegehäuse habe ich angeschraubt, die Kabel nach innen verlegt und über ein Loch in das Hauptgehäuse gefühlt. Außerdem musste ich zwei Öffnungen für die LED und die Anschlussbuchse für das Thermometer bohren.

WLAN Grillthermometer - Innenansichten
WLAN Grillthermometer – Innenansichten

Und hier das komplette, zusammengebaute WLAN Grillthermometer:

Das fertige WLAN Grillthermometer
Das fertige WLAN Grillthermometer

Danksagung

Und wieder einmal bedanke ich mich bei fleißigen Künstlern, die ihre Bilder auf Pixabay zur Verfügung gestellt haben. In meinem Beitragsbild habe ich ganz oder in Teilen folgendes verwendet:

4 thoughts on “WLAN Grillthermometer

  1. Zum Thema LED als Aktivitätsanzeige hätte ich noch einen:
    Die NICHIA NSPR510GS (5mm, rot) ist für so etwas bei Akku- / Batteriebetrieb gut geeignet, da man sie bereits mit ca. 10µA (!) zum Leuchten bringen kann. Ich verwende eine an einem selbst gebauten Mikrofon mit Verstärker, das mit 2 CR2032 in Serie betrieben wird, mit einem Vorwiderstand von 410k :-).
    Grüße, Stefan

    1. 10µA? Cool! Muss ich mir mal anschauen. Die ca. 10mA „normaler“ LEDs gehen bei Dauerbetrib tatsächlich ziemlich auf den Akku. Vielen Dank und viele Grüße, Wolfgang

  2. Cooles Projekt!
    Falls sie die grafische Darstellung aufs Smartphones/Tablet/Computer bringen möchten, dann geht das mit JavaScript und einem canvas Objekt recht gut. Ich bastle ja gerade noch in den letzten Zügen an einer Waage die den Körperschwerpunkt im Browser anzeigen kann… im HX711 Beitrag hatte ich schon einmal davon berichtet. Mein Lösungsansatz ist es, die statischen HTML Dateien aus dem SPIFFS zu liefern und die Werte als JSON. Der Browser setzt beides zusammen und malt die Messpunkte in das canvas Objekt. Das funktioniert erstaunlich reibungslos.
    Beste Grüße und danke für diesen Beitrag.

    1. Hi, vielen Dank für die Hinweise. Bei JavaScript habe ich noch etwas Nachholbedarf. Ich habe mich mal ein bisschen damit beschäftigt, und das Bisschen ist wieder verschüttet. Guter Anlass mir das mal wieder genauer anzuschauen. VG, Wolfgang

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.