Internet de les coses amb ESP32 i ESP8266

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

Sensor de llum

Projecte del grup 3

En aquest cas s'ha dissenyat un sistema d'alarma que detecta l'obertura d'una caixa forta. Una aplicació mòbil permet consultar l'estat de la caixa forta. El programa del microcontrolador és el següent:

#include <SPI.h>    // Carreguem la biblioteca SPI
#include <WiFiNINA.h>    // Carreguem la biblioteca WiFiNINA
#include  <Adafruit_NeoPixel.h>
#define LDRpin A3
#define server_len 50
#define pag_len 400
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(3, 1, NEO_GRB + NEO_KHZ800);
const char idXarxa[] = "xarxa-wifi";     
const char contrasenya[] = "contrasenya-wifi";   
int lectura;
const String server0 = "script.google.com";
String pagina0 = "";
const String pagina_base = "/macros/s/^^fycbzfYsaYSF4qT2Ggx0o7G_VsaPEQZYYTmrHDetbbj_fiO6o64KyWDRHhLbbResmzVaKj/ex";
char server[server_len];
char pagina[pag_len];
unsigned long darreraConnexio = 0;
const unsigned long periodeConnexio = 10000UL;
bool pendent, completa, redir;
bool ara = false;
float llum;
String data;
int num;
String peticio = "";    // Aquí guardarem una línia de la petició del client
String peticioAux = "";    // i la petició anterior (també ho farem servir de reserva)
int status = WL_IDLE_STATUS;
WiFiSSLClient client;
void setup() {    // Inicialització
  pinMode(3, OUTPUT);
  cadena.begin();  // Inicialitza els NeoPixels        
  cadena.show();
  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(); 
  redir = false;
}
void loop() {    // Programa que es repeteix indefinidament
  // El bucle principal té tres parts: 
  //     1. Gestió dels caràcters que arriben
  //     2. Tractament de les dades rebudes
  //     3. Nova petició quan ha passat el temps
  while (client.available()) {
    // Gestió dels caràcters que arriben
    // Aquest bucle va guardant els caràcters rebuts
    // i espera al moment en que arriba un salt de línia
    char c = client.read();    // Rebem caràcters del servidor
    if (c == '\n') {    // Mirem si és un salt de línia
      peticioAux = peticio;    // Guardem la petició anterior
      peticio = "";    // Ens preparem per a la línia següent
      completa = true;    // Preparat per escriure-ho
    } else {
      peticio += c;    // Afegim el caràcter rebut
    }
    // Quan ha arribat un salt de línia, hem de mirar què ha arribat
    if (completa){  // Ha arribat una línia completa
      if (peticioAux.startsWith("HTTP/1.1 200")){    // Resposta bona
        pendent = true;
      }
      if (peticioAux.startsWith("HTTP/1.1 302")){    // Redireccionament
        redir = true;
      }
      if (redir && (peticioAux.startsWith("Location:"))){
        // Si hi ha redireccionament, hem de buscar l'adreça
        // i extreure'n el servidor i la pàgina
        String adre = peticioAux.substring(peticioAux.indexOf("//") +2);
        String server1 = adre.substring(0, adre.indexOf(".com") +4);
        String pagina1 = adre.substring(adre.indexOf(".com") +4);
        server1.toCharArray(server, 50);
        pagina1.toCharArray(pagina, 400);
        ara = true;
      }
      completa = false;
    }
  }
  // Hi ha una resposta per processar
  // Però ignorarem les dades que ens envia l'script
  if (pendent) {
    pendent = false;
  }
  // Quan toca, tornem a fer una petició
  if (ara || ((millis() - darreraConnexio > periodeConnexio))) {
    if(!ara) {
      lectura = analogRead(LDRpin);
      Serial.print("Lectura = ");
      Serial.println(lectura);
      data = "?";
      data += "l=";
      data += lectura;
      data += "&m=a";
      if (lectura < 1000){
        if (num==0){
          tone(3, 440);
          cadena.setPixelColor(0, 0, 150, 0);  // Pixel 0 vermell
          cadena.show(); // Actualitz            
          delay(2000);
          noTone(3);
          cadena.setPixelColor(0, 0, 0, 0);  // Pixel 0 verd
          cadena.show(); // Actualitz
          num++;
        } 
      } else {
        noTone(3); 
        num=0;
      }
    }
    if (redir){
      redir = false;
    } else {
      pagina0 = pagina_base + data;
      server0.toCharArray(server, server_len);
      pagina0.toCharArray(pagina, pag_len);
    }
    client.stop();
    if (client.connect(server, 443)) {
      Serial.println("S'ha fet la connexió al servidor");
      client.print("GET ");
      client.print(pagina);
      client.println(" HTTP/1.1");
      client.print("Host: ");
      client.println(server);
      client.println("Connection: close");
      client.println();
      // Guardem quan hem fet la connexió
      darreraConnexio = millis();
      Serial.print("Enviat: ");
      Serial.println(data);
    } else {
      Serial.println("connection failed");
    }
    ara = false;
  }
}

El programa de l'script és el següent:

var IdFull = "^^jxRPxZjhCzdUSjSB0hXY5wBB-dEL8yiQeuQteic9Xg"; // Identificador del full de càlcul 
var numFull = 0;  // Número del full amb el que hem de treballar
var numCols =1;
var ara = new Date();
function doGet(e) {
  var resultat = '';
  var camps = new Array(1);  // Valors per guardar a la taula
  var Hora = ara.getHours();
  var Minut = ara.getMinutes();
  var horaActual = Hora + ":" + Minut + " h";
  var titol = "Alerta de seguretat"; // Idioma de la app
  var text = "Avui a les " + horaActual + " s'ha produït una obertura de la caixa forta. \n";
  text = text + "\nHoy a las " + horaActual + " se ha producido una apertura de la caja fuerte. \n";
  text = text + "\nToday at " + horaActual + " the safe has been opened. ";
  // Assignem els paràmetres a variables
  var llum = e.parameter.l; 
  var mail = e.parameter.mail;
  var m = e.parameter.m;
  if ((m=='a')){
    if ((llum == undefined)){
      resultat = 'Falten paràm';
    } else if ((llum < 1000)){
      camps[0] = llum;
      var sh = SpreadsheetApp.openById(IdFull);
      var sheet = sh.getSheets();
      var casant = sheet[numFull].getDataRange().getValues()[sheet[numFull].getLastRow()-1][0];
      sheet[numFull].appendRow(camps);   // Afegeix una fila amb la llista de dades en format matriu 
      resultat = 'Valors guardats';
      if ((casant <1000)){
        return ContentService.createTextOutput(resultat);
      } else {
        var full = sheet[1].getDataRange().getValues();
        range = sheet[1].getLastRow();  // Índex de la darrera filera
        if (range >=1){    // Sabent que no hi ha títols, range és el número de files no buides
          for (let i = 0; i <= range-1; i++) {
            var filera = full[i];    // Agafem la filera i
            var correu_filera=filera[0];
            MailApp.sendEmail(correu_filera, titol, text);
          }
        }
      }
      return ContentService.createTextOutput(resultat);
    } else {
      camps[0] = llum;
      var sh = SpreadsheetApp.openById(IdFull);
      var sheet = sh.getSheets();
      sheet[numFull].appendRow(camps);   // Afegeix una fila amb la llista de dades en format matriu 
      resultat = 'Valors guardats';
      return ContentService.createTextOutput(resultat);
    }
  }
  if ((m=='b')){
    var sh = SpreadsheetApp.openById(IdFull);
    var sheet = sh.getSheets();
    // Llegim les dades del full seleccionat
    var full = sheet[numFull].getDataRange().getValues();
    range = sheet[numFull].getLastRow();  // Índex de la darrera filera (+1 pels títols)
    if (range > 1){    // Si és 1 només hi ha els títols
      var filera = full[range -1];    // Agafem la darrera filera
      var resultat = '';
      var a = filera[0];
      if (Number(a)==a){
        return ContentService.createTextOutput(a); 
      }
    }
    return ;
  }
  if ((m=='c')){
    camps[0] = mail;
    var sh = SpreadsheetApp.openById(IdFull);
    var sheet = sh.getSheets();
    sheet[1].appendRow(camps);   // Afegeix una fila amb la llista de dades en format matriu; 1 és numfull on estan els correus
    resultat = 'Valors guardats';
    return ContentService.createTextOutput(resultat);
  }
}

L'aplicació feta amb App Inventor té tres pantalles. La disposició d'elements a la primera pantalla és:

Pantalla

El programa és el següent:

Programa
Programa
Programa

La disposició d'elements a la segona pantalla és:

Pantalla

El programa és el següent:

Programa

La disposició d'elements a la tercera pantalla és:

Pantalla

El programa és el següent:

Programa

 

 

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