Sensore temperatura wifi

In questo articolo, ti farò vedere come creare un sensore di temperatura wifi che ti consentirà di monitorare a distanza la temperatura di un ambiente e di ricevere aggiornamenti sul proprio smartphone tramite Telegram e posta elettronica in caso di superamento di una soglia impostabile. Ti consiglio di leggere anche l’articolo sul rilevatore di fumi smart con cui si potrebbe accoppiare per creare una stazione di monitoraggio completa

Cosa serve?

Passo 1: Configurazione di Arduino IDE

Ti consiglio di visitare l’articolo in cui spiego in dettaglio come si configura l’ambiente di sviluppo per programmare la scheda, se lo hai già fatto salta direttamente al passo2. Riassumendo:
inizia installando Arduino IDE sul tuo computer, se non l’hai ancora fatto. Successivamente, apri l’IDE e vai su “File” -> “Preferenze”. Nella finestra delle preferenze, copia il seguente URL nel campo “URL aggiuntive per il Gestore schede”:

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Fatto ciò, chiudi la finestra delle preferenze.

Ora, vai su “Strumenti” -> “Scheda” -> “Gestore schede”. Cerca “ESP8266” e installa il pacchetto corrispondente selezionando l’ultima versione disponibile. Dopo l’installazione, seleziona “LOLIN (WEMOS) D1 Mini Lite” come scheda in uso.

Passo 2: Collegamento del sensore di temperatura

Aggancia lo shield del sensore di temperatura DS18B20 sopra il Wemos. Finito! Non servono altri collegamenti.
Quali sono i vantaggi di utilizzare questa soluzione con lo shield DS18B20?

  • Non servono cavi, collegamenti o saldature; il tutto risulta molto compatto.
  • Precisione: il sensore DS18B20 offre una precisione di ±0,5°C nell’intervallo di temperatura compreso tra -10°C e +85°C.
  • Conversione rapida: DS18B20 ha una velocità di conversione rapida, che consente di ottenere velocemente la temperatura misurata.
  • Alimentazione: Il sensore può essere alimentato con una tensione compresa tra 3,0V e 5,5V.
  • Economico, circa un euro comprandolo su AliExpress

Molti progetti didattici usano come shield/sensori come DHT11 o DHT22, hanno una bassa precisione ±2°C e sono più senti nel rilevare la temperatura. Non sono consigliati.

Passo 3: Configurazione di Telegram

Per questo scopo trovi una mia guida su come configurare un bot di Telegram.
Brevemente, apri Telegram sul tuo smartphone o sul tuo computer e cerca il bot chiamato “BotFather”. Questo bot ti aiuterà a creare un nuovo bot Telegram e a ottenere un token di accesso. Avvia una chat con BotFather e segui le istruzioni per creare un nuovo bot. Alla fine, otterrai un token di accesso che utilizzeremo nel nostro codice.

Passo 4: Scrivere il codice del sensore temperatura wifi

Apri Arduino IDE e crea un nuovo sketch. Copia il seguente codice nello sketch:

/* www.lutritech.it

  Sensore di Temperatura WIFI con sistema di notifica tramite invio email tramite SMTP e messaggio tramite BOT su Telegram
  
  https://www.youtube.com/@Lutritech
  https://www.facebook.com/lutritech.it/
  https://www.instagram.com/Lutritech/
  https://twitter.com/lutritech/

*/
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h> //  https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
#include <ArduinoJson.h>
#include <OneWire.h>    //	https://www.pjrc.com/teensy/td_libs_OneWire.html
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <ESP8266WebServer.h>
#define HTTP_WEB_PORT 80

//per invio email
WiFiClient espClient;
char server[] = "mail.smtp2go.com";   // SMTP Server esterno FREE
#define USERNAME "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // Lo Username impostato su smtp2go.com e codificato in BASE64 su https://www.base64encode.org/
#define PASSWORD "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // La password impostata su smtp2go.com e codificata in BASE64 su https://www.base64encode.org/

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
OneWire  ds(D2);  // on pin D4 (a 4.7K resistor is necessary)

ESP8266WebServer http_server(HTTP_WEB_PORT);
String temp = "24"; //default temperatura rilevata
String ip = "x.x.x.x"; //default ip
int isterisi = 0;
int soglia = 35; //default soglia massima della temperatura.
int attesa = 10; //con la soglia massima superata è il tempo che deve passare per l'invio della mail 600 sono circa 10 minuti
int offsetTemp = 7.5; // offset temperatura

// Initialize Telegram BOT
#define BOT_TOKEN "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  // your Bot Token (Get from Botfather)
// Use @myidbot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
#define CHAT_ID "XXXXXXXXX"

const unsigned long BOT_MTBS = 1000; // mean time between scan messages
unsigned long bot_lasttime; // last time messages' scan has been done
X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);

//variabile per il riavvio della scheda Wemos
bool RestartTriggered = false;

void setup(void)
{
  Serial.begin(9600);

  WiFiManager wifiManager;
  wifiManager.setAPCallback(configModeCallback);

  if (!wifiManager.autoConnect("AutoConnectAP")) {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000);
  }

  ip = WiFi.localIP().toString();
  //  Serial.println("Debug ip:");
  //  Serial.println(ip);

  configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org

  bot.sendMessage(CHAT_ID, "Ciao mi sono avviato");
  bot.sendMessage(CHAT_ID, "Ecco la pagina web da visitare: ");
  bot.sendMessage(CHAT_ID, "http://" + ip + "/temp");

  Serial.println("Ecco i comandi dal Browser:");
  Serial.println("http://" + ip + "/temp");


  config_server_routing();
  http_server.begin();

  Serial.println(bot_lasttime);
}

void loop(void)
{
  http_server.handleClient();
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;

  if ( !ds.search(addr))
  {
    ds.reset_search();
    delay(250);
    return;
  }

  if (OneWire::crc8(addr, 7) != addr[7])
  {
    Serial.println("CRC is not valid!");
    return;
  }

  // the first ROM byte indicates which chip
  switch (addr[0])
  {
    case 0x10:
      type_s = 1;
      break;
    case 0x28:
      type_s = 0;
      break;
    case 0x22:
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  delay(1000);
  present = ds.reset();
  ds.select(addr);
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++)
  {
    data[i] = ds.read();
  }

  // Convert the data to actual temperature
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10)
    {
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  }
  else
  {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms

  }
  celsius = ((float)raw / 16.0) - offsetTemp; // tolgo un offset dalla temp rilevata
  // celsius = ((float)raw / 16.0);
  fahrenheit = celsius * 1.8 + 32.0;
  //Serial.println(celsius);
  temp = String(celsius, 1);
  Serial.println(temp); //per debug
  if (celsius > soglia)
  {
    Serial.println("Fa caldo! Soglia Superata ");
    isterisi++;
    Serial.println(isterisi);

    if (isterisi > attesa)
    {
      Serial.println(isterisi);
      sendEmail(temp, soglia);
      bot.sendMessage(CHAT_ID, "ATTENZIONE SOGLIA SUPERATA!\n La temperatura è di:" + temp, "");
      isterisi = 0; //azzero l'isterisi....manderà una nuova mail raggiunta nuovamente la soglia e l'attesa
    }
  } else isterisi = 0; //quando la temperatura torna sotto soglia azzero l'isterisi


  if (millis() - bot_lasttime > BOT_MTBS)
  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages)
    {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }

    bot_lasttime = millis();
  }

 if (RestartTriggered == true) {ESP.restart();}

}


byte sendEmail(String msg, int sogliaVal)

{
  if (espClient.connect(server, 25) == 1)
  {
    Serial.println(F("connected"));
  }

  else

  {
    Serial.println(F("connection failed"));
    return 0;
  }

  if (!emailResp())
    return 0;

  Serial.println(F("Sending EHLO"));
  espClient.println("EHLO www.example.com");
  if (!emailResp())
    return 0;

  Serial.println(F("Sending auth login"));
  espClient.println("AUTH LOGIN");
  if (!emailResp())
    return 0;
  Serial.println(F("Sending User"));

  espClient.println(USERNAME); // Lo Username impostato su smtp2go.com e codificato su codificato in BASE64 su https://www.base64encode.org/
  if (!emailResp())
    return 0;
  Serial.println(F("Sending Password"));
  espClient.println(PASSWORD);          //Password impostata su smtp2go.com e codificato su codificato in BASE64 su https://www.base64encode.org/
  if (!emailResp())
    return 0;
  Serial.println(F("Sending From"));


  Serial.println(F("Sending From"));

  espClient.println(F("MAIL From: [email protected]")); // Enter Sender Mail Id
  if (!emailResp())
    return 0;

  Serial.println(F("Sending To"));
  espClient.println(F("RCPT TO: [email protected]")); // Enter Receiver Mail Id
  if (!emailResp())
    return 0;

  Serial.println(F("Sending DATA"));
  espClient.println(F("DATA"));
  if (!emailResp())
    return 0;

  Serial.println(F("Sending email"));
  espClient.println(F("To:  [email protected]")); // Enter Receiver Mail Id

  // change to your address

  espClient.println(F("From: [email protected]")); // E' l'indirizzo che si vedrà nel campo destinatario della mail ricevuta

  espClient.println(F("Subject: ATTENZIONE SOGLIA TEMPERATURA SUPERATA!"));

  espClient.println(F("Temperatura Rilevata: "));

  espClient.println((msg));

  espClient.println(F("Soglia Impostata: "));

  espClient.println((sogliaVal));

  espClient.println(F("."));
  if (!emailResp())
    return 0;


  Serial.println(F("Sending QUIT"));
  espClient.println(F("QUIT"));
  if (!emailResp())  return 0;

  espClient.stop();
  Serial.println(F("disconnected"));
  return 1;

}



byte emailResp()
{
  byte responseCode;
  byte readByte;
  int loopCount = 0;

  while (!espClient.available())
  {
    delay(1);
    loopCount++;
    if (loopCount > 20000)
    {
      espClient.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }

  responseCode = espClient.peek();
  while (espClient.available())
  {
    readByte = espClient.read();
    Serial.write(readByte);
  }

  if (responseCode >= '4') return 0;

  return 1;
}



void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("CONFIG MODE");
  Serial.println("VISIT");
  Serial.println("http://" + ip);
  delay (2000);

  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

////web server/////

void config_server_routing() {
  http_server.on("/temp", HTTP_GET, handleRoot );
  http_server.on("/login", HTTP_POST, handleLogin );
  http_server.on("/soglia", HTTP_POST, handleSoglia );
}


void handleRoot() {                         // When URI / is requested, send a web page with a button to toggle the LED
  http_server.send(200, "text/html", "<HTML><HEAD><TITLE>Controllo temperatura</TITLE></HEAD><BODY><CENTER><h1>TEMPERATURA : " + temp +
                   "</h1><h2>soglia impostata a: " + soglia + "<br><form action=\"/login\" method=\"POST\"><input type=\"text\" name=\"username\" placeholder=\"Username\"></br><input type=\"password\" name=\"password\" placeholder=\"Password\"></br><input type=\"submit\" value=\"Login\"></form>" +
                   "</h2></CENTER></BODY></HTML>");
}

void handleLogin() {                         // If a POST request is made to URI /login
  if ( ! http_server.hasArg("username") || ! http_server.hasArg("password")
       || http_server.arg("username") == NULL || http_server.arg("password") == NULL) { // If the POST request doesn't have username and password data
    http_server.send(400, "text/plain", "400: Invalid Request");         // The request is invalid, so send HTTP status 400
    return;
  }
  if (http_server.arg("username") == "Admin!" && http_server.arg("password") == "Temp!") { // If both the username and the password are correct
    http_server.send(200, "text/html", "<h1>Welcome, " + http_server.arg("username") + "!</h1><p>Login successful</p>" +
                     "<form action=\"/soglia\" method=\"POST\"><input type=\"number\" name=\"soglia\" placeholder=\"Soglia\" value=\"25\"></br><input type=\"submit\" value=\"Soglia\"></form>"
                    );
  } else {                                                                              // Username and password don't match
    http_server.send(401, "text/plain", "401: Unauthorized");
  }
}

void handleSoglia() {
  String sogl = "";
  sogl = http_server.arg("soglia");
  soglia = sogl.toInt();
  Serial.println("La soglia ora è impostata a : "); //per debug
  Serial.println(soglia); //per debug
  http_server.send(200, "text/html", "<h1>Soglia Configurata</h1>");

}

void handleNewMessages(int numNewMessages)
{
  Serial.print("handleNewMessages ");
  Serial.println(numNewMessages);

  String answer;
  for (int i = 0; i < numNewMessages; i++)
  {
    telegramMessage &msg = bot.messages[i];
    Serial.println("Received " + msg.text);
    if (msg.text == "/help")
      answer = "Ciao Sono LutriBot usa i comandi \n/mostra \n/soglia";
    else if (msg.text == "/mostra")
      answer =  msg.from_name + " la temperatura è: " + temp;
    else if (msg.text == "/soglia")
      answer =  msg.from_name + " la soglia impostata è: " + soglia;
     else if (msg.text == "/riavvia") {
      Serial.println("mi sto riavviando");
      answer = " Mi sto per Riavviare";
      RestartTriggered = true;
    }
    else
      answer = msg.text + " Non lo capisco";

    bot.sendMessage(msg.chat_id, answer, "Markdown");
  }
}

void bot_setup()
{
  const String commands = F("["
                            "{\"command\":\"help\",  \"description\":\"Lutri ti aiuta\"},"
                            "{\"command\":\"soglia\",  \"description\":\"Vedi soglia impostata\"},"
                            "{\"command\":\"mostra\", \"description\":\"Vedi temperatura\"},"
                            "{\"command\":\"riavvia\",  \"description\":\"Riavvialo\"}"
                            "]");
  bot.setMyCommands(commands);
}

Passo 5: Personalizzazione del codice

Nel codice sopra, dovrai apportare alcune modifiche personalizzate:

  • Nel #define BOT_TOKEN, inserisci il token di accesso del tuo bot Telegram. Puoi trovarlo nella chat con BotFather.
  • Nel #define CHAT_ID, inserisci l’ID della chat a cui desideri inviare i messaggi. Puoi ottenere l’ID avviando una chat con il tuo bot e visitando il seguente URL: https://api.telegram.org/bot<token>/getUpdates, sostituendo <token> con il tuo token di accesso.
  • Nei #define USERNAME e #define PASSWORD È necessario codificare il nome utente SMTP e la password SMTP impostati su smtp2go.com nel formato Base64 con il set di caratteri ASCII. Per questo, puoi utilizzare un sito Web chiamato  BASE64ENCODE.
    Ad esempio se la tua password fosse testpassword (escluse le virgolette), sarebbe codificata come dGVzdHBhc3N3b3Jk.
    L’ account free di smtp2go.com ti permette di mandare 1000 mail gratis al mese. Non mi dilungo nella registrazione e configurazione.
  • Il campo attesa, indica il numero di letture consecutive sopra soglia necessarie per essere avvisati, questo permette di non ricevere troppe mail/notifiche per eventuali letture anomale o singoli picchi. Mettendo 600 quindi dovrete aspettare 600 letture sopra soglia prima di ricevere la notifica su telegram e la mail di avviso. Per un test iniziale potete impostare 5 oppure 10.
  • Nel campo offsetTemp, puoi indicare quanti gradi °C levare dalla temperatura rilevata per una maggior precisione. Considera che la scheda Wemos scaldandosi alza la temperatura rilevata dal sensore posizionato sopra.

Passo 6: Caricamento del codice

Collega l’ESP8266 al computer tramite un cavo USB e seleziona la porta corretta in Arduino IDE (Strumenti -> Porta). Carica il codice sul tuo Wemos e premi il pulsante “Carica” nell’IDE.

Passo 7: Come funziona il mio software del sensore di temperatura

Una volta caricato il codice, il Wemos va in modalità access point, collegatevi alla rete wifi aperta “AutoConnectAP” e dopo avere trovato la vostra rete selezionatela e inserite la sua relativa password. A questo punto la scheda tutte le volte che si avvierà cercherà di collegarsi a quella rete e se per qualche ragione non riuscisse entrerebbe nuovamente nello stato di configurazione per poi ripetere il procedimento. Non è necessario quindi ricompilare tutte le volte il firmware per cambiare le credenziali delle reti wifi. Questo grazie alla libreria WifiManager di tzapu https://github.com/tzapu/WiFiManager. Trovate altri esempi di come utilizzarla nell’articolo del rilevatore di fumi e di come si costruisce un robot di sorveglianza.
Una volta connesso alla tua rete Wi-Fi, viene ricordato su Telegram l’indirizzo della pagina web da visualizzare e i comandi configurati nel bot.

Avvio Bot Telegram Con Comandi - lutritech

La pagina web indicata permette di visualizzare l’ultima temperatura rilevata dal sensore DS18B20.
Facendo la login con user e password (Admin! e Temp!) è possibile poi impostare un nuovo valore della soglia di allarme.

Web Server Temperatura - lutritech
WebServer Configurare Soglia - lutritech

Se la temperatura rilevata supera per n volte il valore di soglia, viene inviato la notifica su telegram e la mail.

Notifica Bot Telegram superamento soglia Temperatura - Lutritech
Notifica via mail ricevuta - Lutritech

Se volete stampare un case per proteggere la scheda e il sensore ho realizzato questo case. Potete usare del normale PLA.

Conclusioni sul sensore di temperatura wifi

Con il sensore di temperatura wifi ora puoi ricevere aggiornamenti sulla temperatura direttamente sul tuo smartphone sia con Telegram che con il tuo client di posta. In questo progetto spero che avrai imparato ad inviare mail tramite SMTP server, come si fa un piccola pagina con il web server e infine come si usa un bot di Telegram. Tutto questo grazie alla scheda Wemos grande quanto una moneta da 2 euro..
Le possibilità del suo microcontrollore, l’ESP8266 sono veramente infinite, forse Il limite è solo la nostra fantasia.

Se hai domande o curiosità usa pure il form sotto, ti risponderò appena possibile.

Condivi sui Social

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

2 commenti su “Sensore temperatura wifi”

Torna in alto