Aplicaciones-Moviles-y-Servicios-Telematicos

Materia de Aplicaciones Móviles y Servicios Telemáticos

Regresar

Práctica de Laboratorio 6

DESARROLLO DE UNA APLICACIÓN MÓVIL AVANZADA INTEGRANDO HARDWARE IoT CON CONEXIÓN A LA RED DE LORAWAN

Objetivo de Aprendizaje: Diseñar aplicaciones que utilicen los sensores embebidos en dispositivos móviles para la entrega de información a los usuarios en tiempo real.

Recursos: Sensores IoT simulados, Backend de LoRaWan, Android Studio, FireBase, Ubidots. Duración: 7 horas

Introducción: Los microcontroladores mbed son una serie de placas de desarrollo de microcontroladores ARM diseñadas para la creación rápida de prototipos. El microcontrolador mbed NXP LPC1768 en particular está diseñado para crear prototipos de todo tipo de dispositivos, especialmente aquellos que incluyen Ethernet, USB y la flexibilidad de muchas interfaces periféricas y memoria FLASH. Está empaquetado como un pequeño factor de forma DIP para la creación de prototipos con PCB, tableros y placas de prueba, e incluye un programador USB FLASH incorporado.

newproyect

Incluye 512 KB de FLASH, 32 KB de RAM y muchas interfaces, incluidas Ethernet, host y dispositivo USB, CAN, SPI, I2C, ADC, DAC, PWM y otras interfaces de E / S. El pinout anterior muestra las interfaces de uso común y sus ubicaciones. Tenga en cuenta que todos los pines numerados (p5-p30) también se pueden usar como interfaces DigitalIn y DigitalOut. LoRaWAN es una especificación de redes LPWAN (Low Power Wide Area Network). Tomando como base los niveles OSI, sería capa 2 (Enlace de Datos). Es lo que se conoce como MAC (Media Access Control). LoRaWAN se encarga de unir diferentes dispositivos LoRa gestionando sus canales y parámetros de conexión: canal, ancho de banda, cifrado de datos, etc. En la capa 1 del modelo OSI, capa física, encontramos la tecnología LoRa de comunicación. Esta tecnología permite el envío y recepción de información punto-a-punto. Lo que caracteriza a un dispositivo LoRa es su largo alcance con un mínimo dispositivo. Para ello emplea la técnica de espectro ensanchado, donde la señal a mandar utiliza más ancho de banda que el necesario teóricamente pero que permite una recepción de múltiples señales a la vez que tengan distinta velocidad.

newproyect

Tipos de comunicación

  1. Modo LoRa: Comunicación punto a punto En modo Lora los nodos pueden funcionar con una conexión punto-a-punto (P2P) o mesh la principal característica de este modo es que no se requiere un dispositivo intermediario que administre la comunicación, los dispositivos pueden enviar entre ellos información directamente, esto es perfecto para comunicaciones sencillas y simples por ejemplo controlar el encendido y apagado de un motor.

newproyect

La otra manera es de tipo mesh donde encontramos un nodo que se encarga de coordinar la red, sus desventajas son que está limitada a 255 redes de 255 nodos y a que el nodo coordinador solo puede escuchar un nodo a la vez.

newproyect

  1. Modo LoRaWAN

En modo LoRaWAN los nodos forzosamente se deben conectar a un Gateway que soporta hasta 62,500 y puede escuchar 8 nodos a la vez, para poder unirse a la red y aprovechar las bondades del protocolo el nodo debe enviar una serie de llaves de identificación y seguridad, todos los nodos trabajan en una conexión tipo estrella, los mismos nodos aun estando en movimiento se conectan al Gateway más cercano y con mejor calidad de comunicación, muy similar a como funciona una red celular. En protocolo LoRaWAN existen tres tipos de clases de nodo:

Clase A: La más soportada en casi todos los dispositivos, este tipo de clase ofrece el mayor ahorro de energía debido a que solo entra en modo escucha (llamado ventana RX) después de enviar un dato hacia el Gateway, por eso es ideal para dispositivos que usan una batería. Clase B: Este tipo de dispositivos tiene las ventanas de recepción con base a tiempos predeterminados con el Gateway, este tipo de nodos puede usar una batería o una fuente externa dependiendo de los tiempos asignados de escucha. Clase C: Este tipo de clase ofrece el menor ahorro de energía debido a que siempre está en modo escucha y solo cuando es necesario en modo transmitir, la recomendación es usarlo en dispositivos que cuentan con una fuente externa de alimentación.

Actividades:

Paso 1. Creación de cuenta y configuración de dispositivos en The Things Network (TTN) (10 puntos).

lab7

lab7

lab7

lab7

lab6

lab6

JoinEUI se llena de ceros, y se da click en confirmar para mostrar los parámetros adicionales. Para DevEUI coloquen una clave proporcionada por el profesor, la cual tiene el siguiente formato 01.02.03.XX.XX.04.05.06. No hacer click en generate.

lab6

lab6

NOTA: Anotarlos en el formato

Nota: Verificar que DevEUI esté en formato lsb o msb, respectivamente.

Paso 2: Preparación del entorno de desarrollo a) Abrir Arduino IDE para instalar las placas de desarrollo SAMD, tanto de Arduino como de Adafruit seleccionando la ruta “Tools > Board > Boards Manager”.

lab6

b) En caso de que no aparece la placa Adafruit SAMD Boards debe ingresar a List of 3rd party Boards Manager URLs para copiar este enlace Adafruit. Luego ingresar a la ruta de Arduino IDE > Preferences para colocar el enlace copiado en la sección de Additional boards manager URLs y dar clic en OK, como sigue:

lab6

c) Ahora si aparece la placa de Adafruit SAMD Boards

lab6

lab7

lab7

Paso 3: Conexión del Adafruit Feather M0 con el sensor DHT22

lab7

Ilustración 1: Esquemático conexión del sensor DHT22 y Adafruit Feather M0

Nota: El pin correspondiente a data debe estar conectado a un pin digital del Adafruit Feather M0. Además, verificar que el número del pin corresponda con la programación implementada a continuación.

Paso 4: Programación del microcontrolador.

lab7

Paso 5: Envío de mensajes hacia TTN

lab7

lab7

lab7

Nota: La red utilizada para el envío constante de datos hacia los dispositivos configurados en la plataforma The Things Network (TTN) es propia, el estándar es Wi-Fi. Previamente, fue necesario configurar los dispositivos para que estén conectados a la red propia y lograr una comunicación continua entre ellos.

Paso 6: Decodificador

lab7

lab7

Creamos el decoder con el siguiente código:

function decodeUplink(input) {
  t=sflt162f((input.bytes[1]<<8)+input.bytes[0])*100;
  h=sflt162f((input.bytes[3]<<8)+input.bytes[2])*100;
  return {
    data: {
      humedad: h,
      temp: t
    },
    warnings: [],
    errors: []
  };
}
 	function sflt162f(rawSflt16){
  // rawSflt16 is the 2-byte number decoded from wherever;
  // it's in range 0..0xFFFF
  // bit 15 is the sign bit
  // bits 14..11 are the exponent
  // bits 10..0 are the the mantissa. Unlike IEEE format,
  // the msb is explicit; this means that numbers might not be normalized, but
  // makes coding for underflow easier.
  // As with IEEE format, negative zero is possible, so we special-case that in
  // hopes that JavaScript will also cooperate.
  //
  // The result is a number in the open interval (-1.0, 1.0);

  // throw away high bits for repeatability.
  rawSflt16 &= 0xFFFF;

  // special case minus zero:
  if (rawSflt16 == 0x8000)
    return -0.0;

  // extract the sign.
  var sSign = ((rawSflt16 & 0x8000) !== 0) ? -1 : 1;

  // extract the exponent
  var exp1 = (rawSflt16 >> 11) & 0xF;

  // extract the "mantissa" (the fractional part)
  var mant1 = (rawSflt16 & 0x7FF) / 2048.0;

  // convert back to a floating point number. We hope that Math.pow(2, k) is
  // handled efficiently by the JS interpreter! If this is time critical code,
  // you can replace by a suitable shift and divide.
  var f_unscaled = sSign * mant1 * Math.pow(2, exp1 - 15);

  return f_unscaled;
}

lab7

lab7

Paso 7: Creación de mensajes Callbacks hacia Base de datos externa (15 puntos)

NOTA: Utilizaremos la aplicación del Laboratorio 2 (Se requiere haber iniciado sesión con FireBase para poder acceder a la base de datos).

lab7

Nos dirigimos a la página de TTN, seleccionamos en la parte izquierda de la opción Integrations, Webhooks.

lab7

lab7

lab7

lab7

Para Enabled Messages se marcará la opción UpLink Message

lab7

Finalmente, damos clic en “Add Webhook”.

lab7

Ahora necesitamos llenar la base datos de FireBase con algunos registros para poder visualizarlos posteriormente en la aplicación.

Después un tiempo de recibir datos, debe presentarse en la base de FireBase.

lab7

Paso 8 Observar el mensaje desde la aplicación del teléfono (25 puntos)

App/res/layout/activity_perfil_usuario.xml

lab7

lab7

Agregamos la función irRegistros(). Y se la asignamos al botón Ver registros.

App/java/PerfilUsuario.java

public void irRegistros(View view){ 
    Intent intent = new Intent(this, registros.class);
    startActivity(intent);
}

App/res/activity_perfil_usuario.xml

<Button
    android:id="@+id/btnVerRegistros"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="irRegistros"
    android:text="Ver Registros" />
public class registros extends AppCompatActivity {
    DatabaseReference db_reference;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_registros);
        db_reference = FirebaseDatabase.getInstance().getReference().child("GrupoN");
        leerRegistros();
    }
    public void leerRegistros(){}

Nota: Recuerde que para la variable db_reference debe obtener la referencia a los registros de su grupo, por lo que debe cambiar la N por el número de su grupo.

lab7

Código:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".registros" >

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Registros"
        android:textSize="30sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/TituloTemp1"
            android:layout_width="211dp"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <TextView
                android:id="@+id/TituloTemp2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Temperatura" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/TituloHumedad1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <TextView
                android:id="@+id/TituloHumedad2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Humedad" />
        </LinearLayout>
    </LinearLayout>

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/ContenedorTemp"
            android:layout_width="211dp"
            android:layout_height="match_parent"
            android:orientation="vertical"/>
        <LinearLayout
            android:id="@+id/ContenedorHum"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" />
    </LinearLayout>
</ScrollView>
</LinearLayout>

public void leerRegistros(){
    db_reference.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
                mostrarRegistrosPorPantalla(snapshot);
            }
        }
        @Override
        public void onCancelled(DatabaseError error) {
            System.out.println(error.toException());
        }
    });
}

public void mostrarRegistrosPorPantalla(DataSnapshot snapshot){}

public void mostrarRegistrosPorPantalla(DataSnapshot snapshot){

LinearLayout contTemp = (LinearLayout) findViewById(R.id.ContenedorTemp);
LinearLayout contHum = (LinearLayout) findViewById(R.id.ContenedorHum);

String tempVal = String.valueOf(snapshot.child("uplink_message").child("decoded_payload").child("temperatura").getValue());
String humVal = String.valueOf(snapshot.child("uplink_message").child("decoded_payload").child("humedad").getValue());

TextView temp = new TextView(getApplicationContext());
temp.setText(tempVal+" °C");
contTemp.addView(temp);

TextView hum = new TextView(getApplicationContext());
hum.setText(humVal+" %");
contHum.addView(hum); } ``` 

⚠️Importante: Recuerde que en esta práctica no debe de hacer uso de las funciones leerTweets() y escribirTweets(info_user.get(“user_name”)) ubicadas en la clase PerfilUsuario.java por lo que puede eliminar el código o comentarlo.

RESULTADO:

lab7

TAREAS DE DESAFÍO (20 puntos)

lab7

lab7

lab7

lab7

Nota: (Adjunte capturas de pantalla del detalle de la actividad de las variables humedad y temperatura).

Formato de la práctica

La práctica de laboratorio será desarrollado en el siguiente formato:

Importar el archivo json a la Realtime Database mediante la consola de Firebase.