9 de julio de 2019

NodeMCU: proyecto "botón del pánico" (VI-A): la hoja de cálculo y su script.

Lo primero es crear una hoja de cálculo Google Spreadsheet.

Este es su aspecto inicial.


Se recoge la fecha y la hora, en la segunda fila, y, las estaciones permanecen desactivadas con un cero. Si escribo un 1 se activarán.

A partir de la fila 5 se recogerá además un histórico de las pulsaciones que se hayan hecho en las estaciones. Por ejemplo, mi NodeMCU configurado como estación A, al pulsarlo varias veces ha dado este resultado:


Para conseguirlo hay que programar un script de Google, y publicarlo como web app. Dirígete en la hoja a Herramientas >> Editor de secuencias de comando y empieza a escribir el código...

function doGet(e) { // función que se activa tras una petición GET
 
//https://script.google.com/a/macros/s/[codigo]/exec?estacion=X&activo=1 --> ejemplo
 
  // *** Cargando los valores obtenidos como GET ***
  var parametros = JSON.stringify(e);
 
  // Para la versión de depuración, no necesita estar generando la petición
  // var e = JSON.parse('{"parameter":{"estacion":"limpiar","activo":"1"},"contextPath":"","contentLength":-1,"queryString":"estacion=C&activo=1","parameters":{"estacion":["C"],"activo":["1"]}}'); // Cargar para no estar ejecutando la aplicación
 
  // *** Obtiene los valores que necesito para trabajar ***
  var estacion = e.parameter.estacion; // variables que se han recibido. ESTACION
  estacion = estacion.toUpperCase();
  var activo = e.parameter.activo; // variables que se han recibido. ACTIVO
  var columna = estacion.charCodeAt(0)-62; // Código ascii -62; la "A" es 65, luego da el valor 3, correspondiente a la tercera columna
 
  // *** Obtiene la hoja de cálculo ***
  var sheet = SpreadsheetApp.getActiveSheet(); // Obtiene la hoja dentro de la hoja de cálculo actual.
  var ultimalinea = sheet.getLastRow(); // obtiene la última línea
 
  // Fechas y horas actuales.
  var fecha=Utilities.formatDate(new Date, "GMT+1", "dd/MM/yyyy");
  var d = new Date();
  var hora = d.toLocaleTimeString();
 
  // *** Distingue si hay o no un valor válido
  if (columna>=3 && columna<=7 && estacion.length==1) { // si es una sola letra, una columna
 
    // *** Escribe el valor en unas celdas ***
    sheet.getRange(2,columna).setValue(activo); // fila y columna, empezando por cero...
    // Escribe sea cual sea el valor, o Cero o Uno
   
    // *** Si el valor está activo(1), entonces pone también la fecha y la hora del último registro.***
    if (activo==1) {
      sheet.getRange(2,1).setValue(fecha); // Obtiene la fecha
      sheet.getRange(2,2).setValue(hora); // obtiene la hora
      // Y lo va almacenando...      
      sheet.getRange(ultimalinea1,1).setValue(fecha);
      sheet.getRange(ultimalinea1,2).setValue(hora);
      sheet.getRange(ultimalinea1,columna).setValue("Estación "estacion" se activa");
      sheet.getRange(ultimalinea1,columna).setFontColor("darkgreen");
      sheet.getRange(ultimalinea1,columna).setBackground("#AAFFAA");
    } else if (activo==0) {
      // Y lo va almacenando...
      sheet.getRange(ultimalinea1,1).setValue(fecha);
      sheet.getRange(ultimalinea1,2).setValue(hora);
      sheet.getRange(ultimalinea1,columna).setValue("Estación "estacion" se desactiva");
      sheet.getRange(ultimalinea1,columna).setFontColor("darkred");
      sheet.getRange(ultimalinea1,columna).setBackground("#FFAAAA");
    }
   
    Logger.log(e.parameter.estacion);
    Logger.log(e.parameter.activo); // Visualiza parametros de la estación
    Logger.log(columna);
    Logger.log("Última línea " ultimalinea);
   
    // *** Refresco ***
    SpreadsheetApp.flush();
   
    // return HtmlService.createHtmlOutput("<p>Insertado un dato en la hoja: estación "+estacion+" y activo: "+activo+"</p>");  
    // return ContentService.createTextOutput(JSON.stringify(construyeJSON("1","Estación "+estacion+" activo: "+activo))).setMimeType(ContentService.MimeType.JSON);
    // return HtmlService.createHtmlOutput(JSON.stringify(construyeJSON("1","Estación "+estacion+" activo: "+activo.toString())));      
   
    var output = HtmlService.createHtmlOutput('EMPEZAR'JSON.stringify(construyeJSON("1","Estación "estacion" activo: "activo))'TERMINAR');
    // output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
    return output;
 
  // Caso de que la variable estación sea la palabra TODOS, activa o desactiva...
  } else if (estacion.toUpperCase()==="TODOS" || estacion.toUpperCase()==="TODAS") {
   
    // En el caso que quiera desactivarlas o activarlas todas
    sheet.getRange(ultimalinea1,1).setValue(fecha);
    sheet.getRange(ultimalinea1,2).setValue(hora);
    sheet.getRange(2,1).setValue(fecha); // Obtiene la fecha
    sheet.getRange(2,2).setValue(hora); // obtiene la hora
   
    var activacion = "";
    var colortexto = "";
    var colorfondo = "";
    if (activo==1) {
      activacion="se activan";
      colortexto="darkgreen";
      colorfondo="#AAFFAA";
    } else {
      activacion="se desactivan";
      colortexto="darkred";
      colorfondo="#FFAAAA";
    }  
   
   for (var i=3;i<=7;i++) {  // por cada valor de columna
      sheet.getRange(2,i).setValue(activo); // Escribe el valor que corresponda
      sheet.getRange(ultimalinea1,i).setValue("Estación "estacion" "activacion);
      sheet.getRange(ultimalinea1,i).setFontColor(colortexto);
      sheet.getRange(ultimalinea1,i).setBackground(colorfondo);
    }
   
    // *** Refresco ***
    SpreadsheetApp.flush();
   
    // return HtmlService.createHtmlOutput("<p>Insertados datos en la hoja: estación "+estacion+" y activo: "+activo+"</p>");
    // return ContentService.createTextOutput(JSON.stringify(construyeJSON("1","Todas las estaciones "+activacion))).setMimeType(ContentService.MimeType.JSON);
    // return HtmlService.createHtmlOutput(JSON.stringify(construyeJSON("1","Todas las estaciones "+activacion)));  
    var output = HtmlService.createHtmlOutput('EMPEZAR'JSON.stringify(construyeJSON("1","Todas las estaciones "activacion))'TERMINAR');
    // output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
    return output;
 
  // Caso que mande la palabra limpiar, con lo que borra las celdas desde la fila 5
  // Y pone a cero todas las estaciones
  } else if (estacion.toUpperCase()==="LIMPIAR") {
   
    // Poner a cero todas las estaciones
    sheet.getRange("A2:G2").setValue(null);
    sheet.getRange("C2:G2").setValue(0); // valores de cero en todas las estaciones.
   
    // Limpia los registros de datos
    var rangoLimpiar = sheet.getRange("A5:G"(ultimalinea200));
    rangoLimpiar.clearContent();
    rangoLimpiar.setBackground(null);
   
   
    // *** Refresco ***
    SpreadsheetApp.flush();
   
    // return HtmlService.createHtmlOutput("<p>Limpiados los registros de la hoja.</p>");
    // return ContentService.createTextOutput(JSON.stringify(construyeJSON("1","Se limpian todos los datos de la hoja"))).setMimeType(ContentService.MimeType.JSON);
    var output = HtmlService.createHtmlOutput('EMPEZAR'JSON.stringify(construyeJSON("1","Se limpian todos los datos de la hoja"))'TERMINAR');
    // output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
    return output;
   
  } else { // Fin del if que reconoce la columna
   
    Logger.log("Estación fuera del rango");
   
  }
 
}

/* *** Otras funciones **** */

function construyeJSON(success, comentario) {
  var json = {
    'exito':success,
    'comentario':comentario,
  };
  return json;
}

= = = = = = = = = =

1.- función doGet. Esta función recibe un parámetro tipo JSON (e) desde una cadena GET. Comentada en la línea 3 aparece la cadena que usaremos "https://script.google.com/a/macros/s/[codigo]/exec?estacion=X&activo=1". El código lo recibiremos al publicar el script como web app.

2.- En la línea 6, se obtiene en la variable parametros la cadena JSON en formato string. No se usa posteriormente.

3.- Entre las líneas 12 y 15 se extraen los datos: estacion que uso (cinco estaciones de la A a la E), activo (si se activa - 1 - o se desactiva - 0 -) y la columna de la hoja de cálculo según la estación que manda el dato.

4.- Líneas 18 y 19. En la variable sheet se hace referencia la objeto de la actual hoja de cálculo y ultimalinea a la última fila escrita.

5.- Líneas 22 a la 24. Se calcula la fecha y hora actual.

6.- Línea 27. Si se cumple la condición de que columna está entre el número 3 y 7 (A y E) y además estación es una sola letra, entonces en la línea 30 se escribe, en la fila 2 y la columna correspondiente el valor activo que se ha enviado. El if del 34 al 50 lo que hace es, si se activa, escribir la fecha y hora de activación en la línea 2 y un registro en la primera línea vacía tras la última escrita en el registro. Si se desactiva, sólo lo escribe en el registro. La fecha y hora de la línea 2 será por tanto la de la última activación de alguna estación.

7.- De la 52 a la 55 se hacen varias salidas Logging para visualizar el proceso. En la 57 se fuerza el refresco de la hoja de cálculo.

8.- De la 64 a la 66 se produce un envío de información tipo HTML. Una cadena tipo JSON (llama a la funcion de la línea 40) con dos parámetros "exito" y "comentario", encerradas entre las palabras EMPEZAR y TERMINAR. Ya veremos por qué... Si tuvimos exito se recibe un valor de 1 en la variable y de comentario el nombre de la estación y si se activó o no.

9.- En la línea 69 tenemos la condición de que la variable estación sea la palabra "todos" o "todas". El código que le sigue escribe un registro de 1 (ó 0) en todas las estaciones de la línea 2 y en el histórico. De forma similar se refresca la hoja de cálculo y se envía una información tipo HTML de forma similar a la anterior con el comentario "Todas las estaciones se activan|desactivan".

10.- La línea 109 considera el caso de recibir la palabra "limpiar" en la variable estacion. Las siguientes líneas limpian el registro e inicializan la fila 2. Asimismo se refresca la hoja de cálculo y se envía información HTML de forma similar a los casos anteriores.

= = = = = = = = = = 

Publicación de la aplicación web.


Una vez escribimos el código lo publicamos. Vamos al menú PUBLICAR>>IMPLEMENTAR COMO APLICACIÓN WEB. 


Publicamos como "Yo" y "cualquier persona, incluso anónima" para que nuestros NodeMCU no tengan problemas de comunicación (tengo que estudiar el caso de una comunicación más restringida). Escogemos una nueva versión siempre que realice un cambio. Al actualizar me redirige a otra ventana y entonces, 


de esta copio la URL que me aparece, seleccionando en la caja todo el texto.  Este código acaba en exec

Si me voy a una pestaña nueva del navegador y escribo en la barra de direcciones https://script.google.com/macros/s/[codigo]/exec?estacion=A&activo=1 + INTRO veré como se escribe un dato en la hoja. Cambia las estaciones de la A a la E, activo 0 y 1, y verás activándose o desactivándose las estaciones. Si escribo las palabras "todos", "todas" o "limpiar" referidas al parámetros estacion, verás como se activan o descativan todas o se limpia la hoja. 

En cualquier caso, al usar la URL,en la pantalla aparecerá un mensaje como: EMPEZAR{"exito":"1","comentario":"Estación C activo: 1"}TERMINAR que es el valor que retorna el script al producir salidas HTML.








No hay comentarios:

Publicar un comentario