Internet de les coses amb ESP32 i ESP8266

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

Sensor de corrent elèctric

Projecte del grup 2

En aquest cas el sistema detecta si l'aparell està engegat o aturat. Quan està en marxa, es recullen els corrents consumits en mitjana i el seu màxim.

El programa del microcontrolador és el següent:

#include <SPI.h>  // Carreguem la biblioteca SPI
#include <WiFiNINA.h>  // Carreguem la biblioteca WiFiNINA
#define server_len 50
#define pag_len 400
#define SensLec A5  // Pota de lectura del sensor
#define SensRef A6  // Pota de referència del sensor
#define numEsp 2  // Nombre d'espires en el primari
#define numCicles 100 // Nombre de cicles que es mesuraran
const char idXarxa[] = "xarxa-wifi";  // Nom del punt d'accés 
const char contrasenya[] = "contrasenya-wifi";  // Contrasenya de connexió 
const String server0 = "script.google.com";
String pagina0 = "";
const String pagina_base = "/macros/s/^^fycbxwccmJp3XLOEMnnACsHzxgVieOIecHB8iq6137FHRI-goBy-Hfl8t4_iEI_iTcegO_/exec";
char server[server_len];
char pagina[pag_len];
unsigned long darreraConnexio = 0;
const unsigned long periodeConnexio = 10000UL;
unsigned long tempsAnt;
float maxI = 0;  // Valor màxim calculat
float minI = 0;  // Valor mínim calculat
float sumaquad = 0;  // Suma per al càlcul del valor eficaç
float suma = 0;  // Suma per al càlcul de la mitjana
int n = 0;  // Nombre de valors llegits, per fer la mitjana
bool pendent, completa, redir;
bool ara = false;
bool llest = false;
bool ences = false;
float Intensity;
float medI;
float Irms;
String data;
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ó
  tempsAnt = millis();
  Serial.begin(9600);  // Monitor sèrie
  while (!Serial) {
    ;  // Esperem que l'usuari obri el monitor sèrie
  }
  pinMode(LED_BUILTIN, OUTPUT); // Configura el pin como salida
  digitalWrite(LED_BUILTIN, LOW); // Asegura que el LED empiece apagado
  Serial.println(Irms > 1 ? "LED ENCÈS (Intensitat > 1A)" : "LED APAGAT (Intensitat = 1A)");
  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;
  }
  int lec_sensor = analogRead(SensLec);
  int ref_sensor = analogRead(SensRef);
  // Calculem el valor instantani del corrent
  float Iinst = 30 * 3.3 * (lec_sensor - ref_sensor) / 1023 / numEsp;
  sumaquad = sumaquad + (Iinst * Iinst);  // Suma de quadrats
  suma = suma + abs(Iinst);  // Suma de valors absoluts
  n++;
  if((millis() - tempsAnt) > (20 * numCicles)){
    llest = true;
    tempsAnt = millis();
    medI = 1.1107 * suma / n;  // Valor eficaç 
    // calculat a partir de la mitjana
    // pi/2/sqrt(2) = 1.1107
    Irms = sqrt(sumaquad / n);
    if (Irms > 1) {
      digitalWrite(LED_BUILTIN, HIGH);  // Enciende el LED
      ences = true;
    } else {
      digitalWrite(LED_BUILTIN, LOW);  // Apaga el LED
    }
    if(Irms > maxI){
      maxI = Irms;
    }
    if(Irms < minI){
      minI = Irms;
    }
    data = "?";
    data += "i=";
    data += Irms;
    data += "&max=";
    data += maxI;
    data += "&min=";
    data += minI;
    data += "&ences=";
    data += ences;  
  }
  // Quan toca, tornem a fer una petició
  if (ara || ((millis() - darreraConnexio > periodeConnexio))) {
    if(!ara) {
      ;
    }
    if (redir){
      redir = false;
    } else {
      pagina0 = pagina_base + data;
      server0.toCharArray(server, server_len);
      pagina0.toCharArray(pagina, pag_len);
    }
    client.stop();
    if(llest){
      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();
        Serial.print("n = ");
        Serial.print(n);
        Serial.print("   Max = ");
        Serial.print(maxI);
        Serial.print("   Min = ");
        Serial.print(minI);
        Serial.print("   RMSap = ");
        Serial.print(medI);
        Serial.print(" A");
        Serial.print("   RMS = ");
        Serial.print(Irms);
        Serial.println(" A");
        maxI = 0;
        minI = 0;
        sumaquad = 0;
        suma = 0;
        // Guardem quan hem fet la connexió
        darreraConnexio = millis();
        Serial.print("Enviat: ");
        Serial.println(data);
      } else {
        Serial.println("connection failed");
      }
      llest = false;
    }
    ara = false;
    ences = false;
  }
 }

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

var IdFull = "^^YTvG6jkGDEbN88ozLI-39nq76l1lnQFcrdMIWeffjI";  // ID del full de càlcul
function doGet(e) {
  var resultat = '';
  var camps = new Array(8);
  var camps2 = new Array(5);
  var Intensity = e.parameter.i;
  var Maxim = e.parameter.max;
  var Ences = parseInt(e.parameter.ences);
  var EstatAnterior;
  var now = new Date();
  var data = Utilities.formatDate(now, Session.getScriptTimeZone(), "yyyy-MM-dd");
  var hora = Utilities.formatDate(now, Session.getScriptTimeZone(), "HH:mm:ss");
  var sh = SpreadsheetApp.openById(IdFull);
  var fullSheet = sh.getSheetByName("Hoja 1");
  var resumSheet = sh.getSheetByName("Hoja 2");
  var full = fullSheet.getDataRange().getValues();
  var lastrow = fullSheet.getLastRow();
  if (lastrow > 1) {
    var filera = full[lastrow - 1];
    EstatAnterior = filera[0];
    var horaApagatAnterior = filera[5];
  }
  if (Ences == 1) {
    if (EstatAnterior == 'Encès') {
      // Continuació del cicle
      camps[0] = "Encès";
      camps[1] = Intensity;
      camps[2] = Maxim;
      camps[3] = data;
      camps[4] = hora;
    } else {
      // Nou cicle d'encès
      camps[0] = "Encès";
      camps[6] = hora;
      camps[3] = data;
    }
    fullSheet.appendRow(camps);
    resultat = 'Valors guardats';
  } else {
    // Ara està apagat
    if (EstatAnterior == 'Encès') {
      // S'ha apagat, cal calcular cicle i escriure'l
      camps[0] = "Apagat";
      camps[3] = data;
      camps[5] = hora;
      // ======= CÀLCUL DE MITJANA I MÀXIM DEL CICLE =========
      const LLINDAR = 0.5;
      var dades = full;
      var ultimCicle = [];
      var enCicle = false;
      var dataInici = "";
      var horaInici = "";
      for (var i = dades.length - 1; i >= 0; i--) {
        var fila = dades[i];
        var estat = fila[0];
        var intensitat = parseFloat(fila[1]);
        var maxim = parseFloat(fila[2]);
        var dataFila = fila[3];
        var horaFila = fila[4];
        if (estat === "Encès" && intensitat > LLINDAR) {
          ultimCicle.unshift({ intensitat, maxim });
          enCicle = true;
          dataInici = dataFila;
          horaInici = horaFila;
        } else if (enCicle && estat === "Apagat") {
          break;
        }
      }
      if (ultimCicle.length > 0) {
        var suma = ultimCicle.reduce((acc, obj) => acc + obj.intensitat, 0);
        var mitjana = suma / ultimCicle.length;
        var maximCicle = Math.max(...ultimCicle.map(obj => obj.maxim));
        camps2[1] = mitjana;
        camps2[2] = maximCicle;
        camps2[3] = hora;
        resumSheet.appendRow(camps2);
      }
      // ======================================================
      fullSheet.appendRow(camps);
      resultat = 'Valors guardats';
    }
  }
  return ContentService.createTextOutput(resultat);
}

 

 

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