Internet de les coses amb ESP32 i ESP8266

Exemples Referència Plaques   Recursos CITCEA
Projectes Programació Perifèrics   Inici

Guardem les lectures de temperatura i humitat a Google Drive

Google Drive incorpora un full de càlcul (spreadsheet, si ho tenim en anglès). Farem servir aquests fulls de càlcul per crear una taula on guardarem les lectures del sensor de temperatura i humitat. Les dades que guardem en el full de càlcul les podrem llegir, entre moltes altres opcions, des d'una aplicació feta amb App Inventor (vegeu més avall en aquesta mateixa pàgina) o un applet d'IFTTT.

Ara anem a crear la taula. Piquem a Nou i triem full de càlcul. Estem considerant que tenim Google Drive en català, en cas contrari haurem de cercar la traducció corresponent a l'anglès. Se'ns obrirà la pantalla de treball amb la nova taula. Picant on diu Full de càlcul sense títol li podem posar el nom que vulguem. Aquest nom no té cap importància de cara al nostre exemple. Si féssim servir els fuls de càlcul independentment podríem posar els títols de columna a la primera filera del full però no ho farem així. Si ho féssim ens seria complicat descobrir com accedir a la taula des del microcontrolador.

Per facilitar el que necessitarem, farem una mica de "trampa". Picarem a Insereix i triarem l'opció Formulari.... Si tot va bé, tindrem un formulari nou al Google Drive i un nou full al full de càlcul creat. Si surt algun missatge d'error probablement es resoldrà recarregant les pàgines del Google Drive i del full de càlcul.

En lloc de crear columnes a la taula, el que farem serà crear preguntes al formulari. Per fer un formulari senzill, totes les preguntes les posarem del tipus resposta breu amb els paràmetres per defecte. Les preguntes que crearem seran les següents:

Ordre Pregunta
1 Temperatura
2 Humitat

Un cop creat el formulari, picarem el botó Envia i, en la finestra que s'ens obrirà, picarem el botó que es mostra a continuació.

Botó enllaç

Llavors la finestra tindrà un aspecte similar al següent:

Finestra enviar

Piquem al botó copia i se'ns copiarà l'enllaç que haurem d'enganzar en una finestra nova del navegador. En aquesta finestra podrem respondre al formulari. El que escribim no té importància, pot ser qualsevol text. Després podem tancar el formulari.

En el nostre full de càlcul hi apareixerà un full addicional que tindrà tantes columnes com preguntes té el formulari que tindràn com a títol (primera línia) la pregunta corresponent. De fet el full de càlcul tindrà una columna més, al començament, anomenada Marca de temps. Pot passar que les noves columnes triguin una estona en aparèixer.

Un cop introduït, es veuria d'aquesta manera:

Columnes de la taula

Les pàgines i els serveis de Google canvien d'aspecte amb certa freqüència. Les imatges que trobarem en aquest apartat, per tant, poden no correspondre exactament amb les reals. Aquí l'important són els passos, no l'aspecte.

De moment, el nostre full de càlcul és només accessible per a ús personal. Si hi volem accedir des de l'AppInventor ho haurem de canviar. Piquem sobre el botó Comparteix.... Se'ns obrirà una finestra en la que picarem el botó Opcions avançades. On s'indica Qui hi té accés hi deu dir Privat i ho hem de canviar per Activat: tothom que tingui l'enllaç i en el desplegable on diu Pot visualitzar haurem de triar Pot editar. Piquem al botó Desa i tornarem a la finestra anterior on picarem el botó Fet. Ara anem a la pestanya Fitxer i piquem sobre l'opció Publica al web.... Se'ns obrirà una finestra en la que picarem el botó Publica, acceptarem la confirmació i tancarem la finestra.

Ara hem d'obtenir els enllaços necessaris per interactuar amb la taula i els identificadors que tenen les diferents columnes. Atenció: Les dades que heu de fer servir son les de la taula que hagueu creat. Els que es donen com a mostra corresponen a una taula que ja no existeix.

Primerament anirem a la nostra taula i picarem el botó Comparteix.... Allà ens sortirà un enllaç. Piquem el botó Copiar enllaç i ens guardem l'enllaç en algun lloc, per exemple un document del bloc de notes. L'enllaç obtingut serà similar a aquest:

https://docs.google.com/spreadsheets/d/1TThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA/edit?usp=sharing

D'aquesta adreça ens interessa el codi de la taula, que és una seqüència llarga de caràcters situada entre barres. Aquí l'hem marcada en verd perquè sigui fàcil d'identificar.

Amb aquest codi crearem dues adreces que ens faran falta més endavant:

Variable Valor (en el vostre full de càlcul serà diferent)
AdreGet https://docs.google.com/spreadsheets/d/1TThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA/export?format=csv
AdreSelect https://spreadsheet.google.com/tq?tqx=out:csv&key=1TThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA&tq=

Tot seguit, en el menú, anem a la pestanya Formulari i piquem sobre l'opció Ves al formulari actiu. Se'ns obrirà el formulari que havíem creat abans. Hem d'accedir al codi HTML de la pàgina. Això pot ser lleugerament diferent segons el navegador. Piquem sobre el formulari amb el botó dret del ratolí i triem una opció que es pot dir Visualitza el codi font o Visualitza l'origen de la pàgina. Obtindrem una llista llarga de codi HTML que probablement estarà sense estructura i amb els mínims espais possibles. Aquí hi hem de cercar l'adreça que fa servir per enviar les dades del formulari. Cerquem el text form action= i ens l'hauria de trobar un sol cop. Després del signe d'igualtat hi ha d'haver una adreça entre cometes (que comença per https://). Aquesta és l'adreça que ens interessa.

Variable Valor (en el vostre full de càlcul serà diferent)
AdrePost https://docs.google.com/forms/d/e/1FAIpQLSc2qnzs2M1i1NrYumdS4300Pxoj9QGr91reJFdfHLrDTD24kQDA/formResponse

També hem de trobar els identificadors de les columnes de la taula. Per fer-ho fàcil, cerquem el text name="entry.. L'hauria de trobar tants cops com columnes hem creat, és a dir tants com preguntes hem posat al formulari. Els codis, que són els elements que estan entre cometes, ens sortiran en el mateix ordre que les columnes. En el nostre cas eren dues columnes i, per tant, assignarem cada identificador a la columna corresponent.

Camp Identificador
Temperatura entry.1881822567
Humitat entry.504282395

Ara anem a veure el programa que hem de posar al microcontrolador. Aquest programa enviarà les noves dades de temperatura i humitat cada deu segons, aproximadament. En una aplicació pràctica aquest temps podria ser cada hora o cada quinze minuts.

Si en compilar aquest programa us surt un error relacionat amb la biblioteca Adafruit_Sensor.h us recomanem que instal·leu la darrera versió de l'entorn Arduino IDE. Probablement el problema desapareixerà.

// Aquest programa està parcialment basat en els exemples de la pàgina
// https://www.arduino.cc/en/Tutorial/LibraryExamples#wifi1010
#include <SPI.h>    // Carreguem la biblioteca SPI
#include <WiFiNINA.h>    // Carreguem la biblioteca WiFiNINA
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
const char idXarxa[] = "xarxa-wifi";    // Nom del punt d'accés 
const char contrasenya[] = "contrasenya-wifi";    // Contrasenya de connexió 
const char formulari[] = "1FAIpQLSc2qnzs2M1i1NrYumdS4300Pxoj9QGr91reJFdfHLrDTD24kQDA";
const char adrePost[] = "/forms/d/e/1FAIpQLSc2qnzs2M1i1NrYumdS4300Pxoj9QGr91reJFdfHLrDTD24kQDA/formResponse";
String camp1 = "entry.1881822567";
String camp2 = "entry.504282395";
char server[] = "docs.google.com";
float hum, temp;
String data;
int status = WL_IDLE_STATUS;
WiFiSSLClient client;
DHT dht(DHTPIN, DHTTYPE);
void setup() {    // Inicialització
    Serial.begin(9600);    // Monitor sèrie
    dht.begin();
    if (WiFi.status() == WL_NO_MODULE) {
        Serial.println("No s'ha trobat el dispositiu Wi-Fi");
        while (true);    // Bloquegem el programa
    }
    String versio = WiFi.firmwareVersion();
    if (versio < "1.0.0") {
        Serial.println("Convindria actualitzar el firmware");
    }
    while (status != WL_CONNECTED) {
        Serial.print("Connectant a la xarxa ");
        Serial.println(idXarxa);
        status = WiFi.begin(idXarxa, contrasenya);
        delay(10000);    // Ho tornarem a intentar passats 10 s
    }
    Serial.print("Connectat a "); 
    Serial.println(WiFi.SSID());
    Serial.print("Estat de la connexió: ");
    Serial.println(WiFi.status()); 
    Serial.print("Adreça IP del dispositiu: ");
    Serial.println(WiFi.localIP()); 
    Serial.print("Intensitat del senyal: ");
    Serial.print(WiFi.RSSI()); 
    Serial.println(" dBm");
    Serial.println(); 
}
void loop() {    // Programa que es repeteix indefinidament
    if (status != WiFi.status()) {    // Mirem si ha canviat l'estat de la connexió
        status = WiFi.status();
        if (status == WL_AP_CONNECTED) {
            Serial.println("Dispositiu connectat al punt d'accés");
        } else {
            Serial.println("El dispositiu s'ha desconnectat del punt d'accés");
        }
    }
    data = "";
    hum = dht.readHumidity();
    temp = dht.readTemperature();
    data += camp1;
    data += "=";
    data += temp;
    data += "&";
    data += camp2;
    data += "=";
    data += hum;
    data += "&submit=Submit";
    if (client.connect(server, 443)) {
        Serial.println("Connectat");
        client.print("POST ");
        client.print(adrePost);
        client.print("?formkey=");
        client.print(formulari);
        client.println("&ifq HTTP/1.1");
        client.print("Host: ");
        client.println(server);
        client.println("Content-Type: application/x-www-form-urlencoded");
        client.println("Connection: close");
        client.print("Content-Length: ");
        client.println(data.length());
        client.println();
        client.print(data);
        client.println();
        Serial.print("Enviat     T = ");
        Serial.print(temp);
        Serial.print("     H = ");
        Serial.println(hum);
      }
    delay(1000);
    if (!client.connected()) {
        Serial.println();
        Serial.println("Desconnectant");
        client.stop();
    }
    delay(10000);
}

El nostre programa de prova escriu unes quantes coses al monitor sèrie (instruccions Serial.print i Serial.println). Quan ja tinguem clar que el programa funciona, les podem eliminar quasi totes i probablement anirà una mica més ràpid.

Anem a veure un exemple senzill d'aplicació feta amb App Inventor que llegeix els darrers valors de temperatura i humitat que s'han escrit a la taula.

Podríem dissenyar una pantalla amb el següent aspecte:

Disposició dels elements

Propietat Valor Comentaris
Nom Screen1 Aquest nom ja està posat a l'inici i no es pot canviar

Propietat Valor Comentaris
Nom HorizontalArrangement_Menu Aquest nom l'hem de posar en el requadre Components
Width Fill parent
AlignHorizontal Center

Propietat Valor Comentaris
Nom Button_Actualitzar Aquest nom l'hem de posar en el requadre Components
Text Actualitzar
FontBold Activat
TextColor Yellow
BackgroundColor Blue
Shape rounded

Propietat Valor Comentaris
Nom Label_Data Aquest nom l'hem de posar en el requadre Components
Width Fill parent
TextAlignment center

Propietat Valor Comentaris
Nom Label_Temp Aquest nom l'hem de posar en el requadre Components
Width Fill parent
TextAlignment center
FontBold Activat
FontSize 40

Propietat Valor Comentaris
Nom Label_Humi Aquest nom l'hem de posar en el requadre Components
Width Fill parent
TextAlignment center
FontBold Activat
FontSize 40

Propietat Valor Comentaris
Nom Web_Connecta Aquest nom l'hem de posar en el requadre Components

El programa és el següent.

Programa
Programa

A l'hora de mostrar el text hem retallat el camp de data i hora per prescindir dels segons perquè hem considerat que no ens fan falta. També hem posat les unitats a les mesures i adaptat els resultats (que a la taula estan en format anglosaxó) a les nostres normatives separant l'hora amb punt, els decimals amb coma, etc.

 

 

 

 

 

 

 

 

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.