Interaccionar con FireBase desde Arduino


Como  podemos ver en este blog en numerosas  entradas que hablamos de dispositivos de IoT, es  relativamente sencillo construir nuestros  propios dispositivos de IoT con algunos sensores y microcontroladores  como Arduino, NodeMCU, Raspberry  Pi, etcétera , lo cual le permitirán automatizar su hogar apoyándose en estos dispositivos como por ejemplo usando el servicio de Cayenne .

De hecho ,como ejemplo de lo  sencillo  y económico  que puede ser  la construcción de dispositivos   IoT desde un punto de vista más empírico , lo ideal es usar un o NodeMCU ESP-12E para   acceder a Firebase  

 

Picture of Bill of Materials

 NodeMCU ESP-12E  es muy barato (unos 6€)   ,  y al tener  wifi incorporado para conectarse a internet,  ya tenemos los elementos suficientes  para conectarnos a  bases de datos avanzada  en l anube como puede ser Firevase y   gracias a un hardware tan eficiente  (y por supuesto los servicios cloud de Firebase).

Precisamente  FirebaseArduino (abstracción completa de la API REST de Firebase expuesta a través de las llamadas de C ++ de una manera amigable con el cableado.)   es una biblioteca muy útil usada   para simplificar la conexión a la base de datos Firebase desde cualquier cliente Arduino .Esta biblioteca  como podemos imaginar  se encarga de todo el análisis de Json y puede realizar transacciones en tipos C / Arduino puros.

En un post anterior «Primeros pasos con NodeMCU y Firebase»  ya vimos un sencillo ejemplo de como ambos componentes pueden funcionar, Veamos a  a continuación  que podemos hacer c muchas mas cosas con esta famosa librería

 

class FirebaseArduino

Esta es la clase principal para que los clientes de Arduino interactúen con Firebase. Como es habitual con arduino  para referenciarla  y poderla usar necesitamos  introducir  esta libreria con un include  al principio del programa , como por ejemplo

 #include <FirebaseArduino.h>»

Esta implementación está diseñada para seguir las mejores prácticas de Arduino y favorecer la simplicidad sobre todo lo demás. Para casos de uso más complicados y más control, podemos usar la clase Firebase en Firebase.h.

Esta libreria debe ser llamada primero con void begin ( const String y host , const String y auth = «» )  , lo cual inicializa el cliente con el host y las credenciales de base de fuego dados.

Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);  //intentamos conectarnos a la base de datos Firebase con nuestras credenciales

Los parámetros son :

  • host : es decir el  host de base de datos de base de datos de Fierbase , normalmente X.firebaseio.com.
  • auth : credenciales  para la db  que pueden ser  una palabra  secreta o token.

 

Lo más sencillo  precisamente para pasar las credenciales de Firebase   a esta clase es usando  variables que  definiremos al principio del programa:

  • #define FIREBASE_HOST “xxxxxxxxxxxxxxx.firebaseio.com”
  • #define FIREBASE_AUTH “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”

 

Veamos algunas funciones que podemos usar con esta clase:  pushInt,pushFloat, pushBool,pushString,push,setInt, setFloat,setBool,setString,set ,getInt, getFloat,getBool,getString,get,   las relacionadas con Firebaseobject(get,readevent)  .   asi como remove,stream, available,read ,success, failed,error

 

 

String pushInt ( const String & path , int value )

Anexa el valor entero al nodo en la ruta.Equivalente al POST de la API REST. Debe comprobar  success()  después de llamar. Devuelve la clave única del nuevo nodo hijo.

Los parámetros que usa:

  • path : La ruta del nodo padre.
  • value : valor entero que desea agregar al nodo.

 

String pushFloat(const String &path, float value)

Esta función anexa el valor flotante al nodo en la ruta.  Es equivalente al POST de la API REST. Debe comprobar   success()   después de llamar. Devuelve la clave única del nuevo nodo hijo.

Los parámetros que usa:

  • path : La ruta del nodo padre.
  • value : valor flotante que desea agregar al nodo.

String pushBool(const String &path, bool value)

Esta función anexa el valor booleano al nodo en la ruta.  Es equivalente al POST de la API REST. Debe comprobar el resultado de salida con  success()  después de llamar a a funcion . Devuelve la clave única del nuevo nodo hijo.

Los parámetros que usa:

  • path : La ruta del nodo padre.
  • value : valor Booleano que desea agregar al nodo.

String pushString(const String &pathconst String &value)

Esta función anexa el valor de cadena al nodo en la ruta.Es equivalente al POST de la API REST. Debe comprobar el resultado de salida con  success()  después de llamar a a funcion. Devuelve la clave única del nuevo nodo hijo.

Los parámetros que usa:

  • path : La ruta del nodo padre.
  • value : valor de la  cadena que desea agregar al nodo.

 

String push(const String &pathconst JsonVariant &value)

Esta función anexa los datos JSON al nodo en la ruta.Equivalente al POST de la API REST.   Devuelve la clave única del nuevo nodo hijo.

Parámetros

  • path : La ruta del nodo padre.
  • value : los datos JSON que desea agregar al nodo.

 

void setInt(const String &path, int value)

Escribe el valor entero en el nodo ubicado en la ruta equivalente al PUT de la API REST. Debe comprobar el resultado de salida con  success()  después de llamar a a función

Parámetros que usa

  • path : la ruta dentro de su base de datos al nodo que desea actualizar.
  • value : valor entero que desea escribir.

void setFloat(const String &path, float value

Escribe un  valor en coma flotante en el nodo ubicado en la ruta equivalente al PUT de la API REST.Debe comprobar el resultado de salida con  success()  después de llamar a a función

Parámetros necesarios:

  • path : la ruta dentro de su base de datos al nodo que desea actualizar.
  • value : el valor flotante que desea escribir.

void setBool(const String &path, bool value)

Escribe el valor booleano  en el nodo ubicado en la ruta equivalente al PUT de la API REST.  Debe comprobar el resultado de salida con  success()  después de llamar a a función  

Parámetros que usa

  • path : la ruta dentro de su base de datos al nodo que desea actualizar.
  • value :  valor booleano  que desea escribir.

void setString(const String &pathconst String &value)

Escribe el valor de la cadena en el nodo ubicado en la ruta equivalente a la PUT de la API REST. Debe comprobar el resultado de salida con  success()  después de llamar a a función

Parámetros que requiere:

  • path : la ruta dentro de su base de datos al nodo que desea actualizar.
  • value : valor de la cadena que desea escribir.

 

void set(const String &pathconst JsonVariant &value)

Escribe los datos JSON en el nodo ubicado en la ruta.  Equivalente al PUT de la API REST.  Debe comprobar el resultado de salida con  success()  después de llamar a a función

Parámetros necesarios:

  • path : la ruta dentro de su base de datos al nodo que desea actualizar.
  • value : datos JSON que desea escribir.

 

int getInt(const String &path)

Obtiene el valor entero ubicado en la ruta. Debe comprobar el resultado de salida con  success()  después de llamar a a función   Devuelve el valor entero ubicado en esa ruta. Solo será poblado si  success()   es verdadero. Requiere un único  parámetro path : la ruta al nodo que desea recuperar.

 

float getFloat(const String &path)

Obtiene el valor flotante ubicado en la ruta. Debe comprobar el resultado de salida con  success()  después de llamar a a función. Devuelve  un valor flotante ubicado en ese camino. Solo será poblado si un success()  ) es verdadero.

Requiere un único  parámetropath : la ruta al nodo que desea recuperar.

 

String getString(const String &path)

Obtiene el valor de cadena ubicado en la ruta.Debe comprobar el resultado de salida con  success()  después de llamar a a función.   Devuelve el valor de cadena ubicado en esa ruta. Solo será poblado si el   success()   es verdadero.

Requiere un único  parámetropath : la ruta al nodo que desea recuperar.

 

bool getBool(const String &path)

Obtiene el valor booleano ubicado en la ruta.Debe comprobar el resultado de salida con  success()  después de llamar a a función. Devuelve el  valor booleano ubicado en esa ruta. Solo será poblado si el éxito () es verdadero. Requiere un único  parámetro  path : la ruta al nodo que desea recuperar.

Es muy usado para  activar o desactivar un  nivel  lógico  en los pines binarios  en la placa ,por ejemplo para activar una salida a nivel alto  o bajo 

Ejemplo

      bool isLedOn = Firebase.getBool(“led”); // recuperamos el valor del objeto led de la sesión firebase

 

 

FirebaseObjectget(const String &path)

Obtiene el valor del objeto json ubicado en la ruta.Debe comprobar el resultado de salida con  success()  después de llamar a a función. Devuelve el valor FirebaseObject ubicado en esa ruta. Solo será poblado si el éxito () es verdadero.Requiere un único  parámetro path : la ruta al nodo que desea recuperar.

FirebaseObjectreadEvent()

Lee el siguiente evento en una stream ( secuencia).Esto solo tiene sentido una vez que se ha llamado a  stream() 

A la salida FirebaseObject tendrá [«type»] que describe el tipo de evento, [«path»] que describe la ruta efectuada y [«data»] que se actualizaron.

 

 

 

void remove(const String &path)

Elimina el nodo, y posiblemente el árbol completo, ubicado en la ruta.Debe comprobar el resultado de salida con  success()  después de llamar a a funcion.Requiere un único  parámetro path : la ruta al nodo que desea eliminar, incluidos todos sus hijos.

void stream(const String &path)

Inicia la transmisión de los cambios realizados en el nodo ubicado en la ruta, incluido cualquiera de sus elementos secundarios.

Debe comprobar el resultado de salida con  success()  después de llamar a a funcion Esto cambia el estado de este objeto. Una vez que se llama a esto, puede comenzar a monitorear available () y llamar a readEvent () para obtener nuevos eventos.

Requiere un único  parámetro path : la ruta dentro de su db al nodo que desea monitorear.

bool available()

Comprueba si hay nuevos eventos disponibles.Esto solo tiene sentido una vez que se ha llamado a  stream()  .Devuelve si un nuevo evento está listo.

bool success ( ) 

Devuelve   si el último comando fue exitoso.

bool failed ( ) 

Devuelve si el último comando falló.

 

const String &error()

 Devuelve el  mensaje de error del último comando si  failed() es verdadero.

 

 

 

 

 

class FirebaseObject

 

Representa el valor almacenado en Firebase , puede ser un valor singular (nodo de tipo leaf) o una estructura de árbol.

Las  funciones publicas  definidas para esa clase son las siguientes:

 

FirebaseObject ( const char * data ) 

Construir a partir de json.  Requiere un único  parámetro data : cadena formateada JSON.

 

bool getBool ( const String & path = «» ) const

Devuelve el valor como un booleano. .Requiere un único  parámetro optional : ruta en el objeto JSON.

 

int getInt ( const String & path = «» ) const

 Devuelve el  resultado como un entero.Requiere un único  parámetro optional : ruta en el objeto JSON.

 

float getFloat ( const String & path = «» ) const

Devuelve el valor como un flotador..Requiere un único  parámetro optional : ruta en el objeto JSON.

 

String getString ( const String & path = «» ) const

Devuelve el valor como una cadena.Requiere un único  parámetro optional : ruta en el objeto JSON.

 

JsonVariant getJsonVariant ( const String & path = «» ) const

Devuelve el valor como JsonVariant.Requiere un único  parámetro optional : ruta en el objeto JSON.

bool success ( ) const

Devuelve si hubo un error en la descodificación o el acceso al objeto JSON.bool 

 

failed ( ) const

Devuelve si  hubo un error en la descodificación o el acceso al objeto JSON.const 

 

String & error ( ) const

 Devuelve un mensaje de error si  failed()  es verdadero.

 

 

Mas informacion en  https://firebase-arduino.readthedocs.io/en/latest/

Extracción de datos de un pdf desde Java


A veces  necesitamos  extraer información de texto procedente de  ficheros  en formato pdf   por ejemplo  para automatizar la extracción de determinada información  relevante que contengan o simplemente porque deseamos guardar la información editable  en  otro formato mas amigable. En realidad es realmente interesante    intentar   automatizar esta  tarea  pues así nos   evitamos  manipulaciones manuales   y tediosas lo cual seguramente nos hagan perder mucho tiempo  con la gran escasez de este elemento de la vida moderna del que  tampoco disponemos

Vamos  a ver dos métodos  para hacerlo  usando el IDE  de  Eclipse y el lenguaje Java

Método 1; mediante un paso intermedio con conversión previa de los ficheros pdf a ficheros de texto

PDF to TXT Converter es una aplicación de Windows para convertir archivos pdf a archivos de formato de texto sin formato en modo batch. Este programa también admite la conversión de rango de páginas específicas a archivos txt  de modo que después de la conversión, obtendrá el texto editable del documento PDF original

PDF to TXT Converter

Esta  utilidad la podemos descargar   desde  aqui

Hay una pequeña pega con este programa, pues dado que es shareware en la versión gratuita   tiene  bastantes limitaciones ,entre ellas que no se procesaran más de 200 documentos de un sola vez  ( si se intenta con más de esa cantidad   el programa pierde el control)

Un punto a su favor es que permite convertir automáticamente directorios enteros  con contenido de ficheros pdf y de este modo no necesitamos seleccionar  uno a uno cuál de ellos queremos convertir ( pero no olvide que, a no ser que compre la version completa, solo debería contener como máximo 200  ficheros)

Como vemos ,lo interesante de este programa  es que permite convertir los  ficheros pdf a texto  lo cual nos facilitara  procesar estos  muy fácilmente desde   java

Ahora    vamos a   ver un ejemplo    cómo extraer  los metadatos de un documento  de tipo texto obtenido usando el programa anterior

La idea es que a partir de los pdf convertidos previamente a txt , es que iremos  leyendo el contenidos de cada fichero txt e  interpretando las cadenas extraidas de los pdf para buscar  por ejemplo cuatro  meta-datos que necesitamos , haciendo  cuenta del orden en el que aparecen asi como las palabras justo anteriors:
-meta1,
-meta2
-meta3
-meta4:

En esta búsqueda tiene sentido el número de orden en el que aparecen las cadenas anteriores a  la busqueda  pues según el orden en que aparezca corresponderá a un meta-dato u otro.

En este caso meta2 hay que buscarlo dos veces , pero según este orden la cadena siguiente es meta2 o meta4

Veamos el ejemplo;

//*******************************************************
//BLOQUE PRINCIPAL PARA EXTRAER  4 METADATOS de un fichero
//*******************************************************

//abre el fichero
Scanner in =null;
DecimalFormat formateador = new DecimalFormat(«####################»);
Integer contador=0;

//solo procesaremos los ficheros con la extrension txt
if (sub.matches(tipofichero)) try{

in = new Scanner(new FileReader(nombreFichero));
in.useLocale(Locale.ENGLISH);

//lee el fichero palabra a palabra

while (in.hasNext())
{
//lee primera palabra
String palabra = in.next();
caa=palabra;

if (procesa==true)
{
//System.out.println(«Palabra:»+palabra+ «contador=»+contador);

if (contador==1)
{instalacion=palabra;
}
if (contador==5)
{nif=palabra;
}

procesa=false;
contador++;

}

if (caa.matches(«pedido:»))
{
// System.out.println(«<<<Palabra pedido: ENCONTRADA:>>>»);
procesan=true;
contador++;
}

if (caa.matches(«instalación:»))
{
//System.out.println(«<<<<Palabra instalación: ENCONTRADA:>>>>»);//fecha
procesa=true;
contador++;
}

if (caa.matches(«NIF/NIE/Pasaporte:»))
{
// System.out.println(«<<<<Palabra NIF/NIE/Pasaporte: ENCONTRADA>>>>»);
procesa=true;
contador++;
}

//lee números
while (in.hasNextDouble())
{
// lee un double

double d = in.nextDouble();

if (procesan==true)
{
//System.out.println(«Número:»+formateador.format(d)+»contador=»+contador);
if (contador==3)
{pedido=d;
}
if (contador==7)
{linea=d;
}
procesan=false;
contador++;
}

}

} // while (in.hasNext())

//resumen de datos capturados del pdf convertidos en txt y capturada en 4 campos que necesitamos

System.out.println(«Instalacion:»+instalacion); //fecha
System.out.println(«Pedido:»+formateador.format(pedido));
System.out.println(«NIF:»+nif);
System.out.println(«Telefono:»+formateador.format(linea));

….

 

Método 2  directo usando la Liberia ItextPDF

iText es una biblioteca Open Source para crear y manipular archivos PDFRTF, y HTML en Java. Fue escrita por Bruno LowagiePaulo Soares, y otros; está distribuida bajo la Affero General Public License.

El mismo documento puede ser exportado en múltiples formatos, o múltiples instancias del mismo formato. Los datos pueden ser escritos a un fichero o, por ejemplo, desde un servlet a un navegador web.

Más recientemente, ha sido extendida a una biblioteca PDF de propósito general, capaz de rellenar formularios, mover páginas de un PDF a otro, y otras cosas. Estas extensiones son a menudo mutuamente excluyentes. Una clase te permite rellenar en formularios, mientras una clase diferente e incompatible hace posible copiar páginas de un PDF a otro.

El soporte de PDF de iText es, sin embargo, bastante extensivo. Esto soporta firmas basadas en PKI de PDF, cifrado de 40-bit y 128-bit, corrección de colores, PDF/X, gestión de colores por perfiles ICC, y es anfitriona de otras característica

Podemos descargar el fichero itextpdf-5.1.0.jar  desde el respositorio de Maven   o de esta web  http://www.java2s.com/Code/Jar/i/Downloaditextpdf510jar.htm

No debemos olvidar importar el jar desde el Ide  del  Eclipse   en propiedades del proyecto-->Java Build Path–>libraries –>Add External   JARs

Este es un ejemplo  de captura sencilla   de como procesar un pdf directaeente

import java.io.IOException;

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;

public class prueba {

/**
* @param args
*/
public static void main(String[] args) {
try {

PdfReader reader = new PdfReader(«d:/ttttt.pdf»);

System.out.println(«This PDF has «+reader.getNumberOfPages()+» pages.»);
String page = PdfTextExtractor.getTextFromPage(reader, 1);
System.out.println(«Page Content:\n\n»+page+»\n\n»);
System.out.println(«Is this document tampered: «+reader.isTampered());
System.out.println(«Is this document encrypted: «+reader.isEncrypted());

reader.close();
} catch (IOException e) {
e.printStackTrace();
}

}

}

Es importante la sentencia String page = PdfTextExtractor.getTextFromPage(reader, 1);  porque si ponemos 0 o un valor superior daría error

Como   gracias  a la librería podemos capturar la informacion del   fichero pdf y aplicar la clase Sacanne para analizar las cadenas     para buscar determinada  informacion  que queremos catalogar vamos a  ver   el ejemplo anterior  usando los mismos campos  y con la misma casuitica:

Este seria el mismo ejemplo de la  primer parte  , pero usando directamente los fichero pdf sin convertir a pdf:

import java.awt.Rectangle;
import java.awt.print.PageFormat;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.List;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;

import java.io.IOException;

import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Scanner;
import java.util.Locale;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;

import java.io.StringReader;

import java.util.Locale;
import java.util.Scanner;

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;

public class Main {

/**
* @param args
*/

public static void main(final String[] args) throws IOException {

String instalacion=»»;
String nif=»»;
double pedido=0;
double linea=0;
boolean procesa=false;
boolean procesan=false;
String tipofichero=»pdf»; // solo tomaremos ficheros con esta extension
String caa = substring(20);

String ruta = «D:\temp\ficheros\»;
String ficherox=»28348758018_20181201000002.pdf»;
String fichero=ruta+ ficherox;
System.out.println(«Fichero a analizar =» +ficherox);

int numero=ficherox.length()-3; //calcula donde empieza la extension del fichero
// System.out.println(«numero=»+numero);
String sub =ficherox.substring( numero); //calcula la extension del fichero
System.out.println(«Extension del fichero :»+sub);

//abrimos el PDF
PdfReader reader = new PdfReader(fichero);
int pages = reader.getNumberOfPages();
System.out.println(«Este PDF tiene «+pages+» paginas.»);

//empezamos la coversion a pdf
String page = PdfTextExtractor.getTextFromPage(reader, 1); ////<———————————————–aqui da errror
System.out.println(«Contenido del documento de la pagina «+pages);
System.out.println(«\n\n»+page+»\n\n»);

/////////////////////////////////////////////////////////////////////
//solo procesaremos los ficheros con la extrension pdf
////////////////////////////////////////////////////////////////////

if (sub.matches(tipofichero))

/// try

{

//para procesar el texto lo copiamos a una cadena
String nombreFichero = page ; //Fichero;

System.out.println(«Convertido salida del conversor a un String «);

//borra el scanner
// Scanner in =null;

//formatos de numeros
DecimalFormat formateador = new DecimalFormat(«####################»);

//inicializa conatdor
int contador=0;

//in = new Scanner(new FileReader(nombreFichero));///AQUI ESTA EL PROBLEMA PUES SCANNER NO EST ACEPTADNO EL STRING

Scanner in = new Scanner(nombreFichero);

in.useLocale(Locale.ENGLISH);
System.out.println(«Es correcto el pdfl Convertido salida del conversor a un String «);
//lee el fichero palabra a palabra

while (in.hasNext()) //leemos toda la cadena
{
//lee primera palabra
String palabra = in.next();
caa=palabra;

if (procesa==true)
{
//System.out.println(«Palabra:»+palabra+ «contador=»+contador);

if (contador==1)
{instalacion=palabra;
}
if (contador==5)
{nif=palabra;
}

procesa=false;
contador++;

}

if (caa.matches(«pedido:»))
{
// System.out.println(«<<<Palabra pedido: ENCONTRADA:>>>»);
procesan=true;
contador++;
}

if (caa.matches(«instalación:»))
{
//System.out.println(«<<<<Palabra instalación: ENCONTRADA:>>>>»);//fecha
procesa=true;
contador++;
}

if (caa.matches(«NIF/NIE/Pasaporte:»))
{
// System.out.println(«<<<<Palabra NIF/NIE/Pasaporte: ENCONTRADA>>>>»);
procesa=true;
contador++;
}

//lee números
while (in.hasNextDouble())
{
// lee un double

double d = in.nextDouble();

if (procesan==true)
{
//System.out.println(«Número:»+formateador.format(d)+»contador=»+contador);
if (contador==3)
{pedido=d;
}
if (contador==7)
{linea=d;
}
procesan=false;
contador++;
}

}

} // while (in.hasNext())
in.close();

//resumen de datos capturados del pdf convertido en txt

System.out.println(«Instalacion:»+instalacion); //fecha
System.out.println(«Pedido:»+formateador.format(pedido));
System.out.println(«NIF:»+nif);
System.out.println(«Telefono:»+formateador.format(linea));

//fin de metatados de un documento INDIVIDUAL en el xml

}

}

private static String substring(int i) {
// TODO Auto-generated method stub
return null;
}//CLASS
}

 

 

Con esta librería como vemos  podemos procesar  de un modo relativamente sencilllo   cualquier contenido de un fichero  pdf    de un modo muy potente  como acabamos de ver .