ANDROID NFC CON FIREBASE Y RASPBERRY PI
Descripción del proyecto
Cuando el celular se acerca al tag NFC, lee la información (previamente guardada en este Tag), a través de NDEF (NFC Data Exchange Format) y con Java (Android), se compara el texto obtenido del tag, para luego comunicarse con API de Firebase,
Ejemplo, si lo que se leyó del tag1 es “sala” entonces cambia el estado en firabese en la URL determinada.
Paralelo a esto, en Raspberry Pi (Python), se está accediendo continuamente a la misma URL de Firebase, lo que permite obtener el valor de los estados de (“sala” y “habitación”) y posteriormente controlar el GPIO dependiendo el valor de estos estados.
ALGO DE TEORÍA
Tecnología NFC
Near field communication (NFC, comunicación de campo cercano en español) es una tecnología de comunicación inalámbrica, de corto alcance y alta frecuencia que permite el intercambio de datos entre dispositivos (tomado de wikipedia)
Para más información sobre como se trabaja está tecnología en Android
http://developer.android.com/intl/es/guide/topics/connectivity/nfc/index.html
Para más información sobre como se trabaja está tecnología en Android
http://developer.android.com/intl/es/guide/topics/connectivity/nfc/index.html
NDEF
The NFC Data Exchange Format (Formato de intercambio de datos) (NDEF) es un formato de datos normalizado que se puede utilizar para intercambiar información entre cualquier dispositivo NFC compatible y otro dispositivo NFC o etiqueta
En android
En android
1. Instalar NFC Tools en Android.
Seleccionar escribir, y Añanidr un registro de texto, luego acerque la tarjeta al lado trasero del celular.
Si le arroja algún error, puede primero formatear la tarjeta o Tag NFC, y volver a intentar la escritura.
Para este ejemplo, hay que escribir "sala" (Sin comillas) y en otro tag, "habitacion", (tal como está sin acento)
2. Aplicación Android
Les comparto el proyecto en Android Studio, ahi pueden encontrar el apk
El proyecto android se encarga de procesar la lectura del tag NFC, y de acuerdo a al texto obtenido se actualiza el estado en firebase, de una URL en especifico.
Solo voy a mostrar el main.java que es el archivo donde está la lógica.
main.java
Ver código completo
Ver código completo
package com.example.user.minfc; import android.app.PendingIntent; import android.content.Intent; import android.content.IntentFilter; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.Ndef; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; import com.firebase.client.DataSnapshot; import com.firebase.client.Firebase; import com.firebase.client.FirebaseError; import com.firebase.client.ValueEventListener; import java.io.UnsupportedEncodingException; import java.util.Arrays; public class MainActivity extends AppCompatActivity { public static final String MIME_TEXT_PLAIN = "text/plain"; public static final String TAG = "NfcDemo"; Firebase fire_sala, fire_habitacion; private TextView textLog = null; private TextView textSala, textHabitacion; private NfcAdapter mNfcAdapter = null; private Boolean ultimoEstadoSala, ultimoEstadoHabitacion; private ToggleButton toggleButtonSala, toggleButtonHabitacion; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fire_habitacion.setAndroidContext(this); fire_sala.setAndroidContext(this); fire_sala = new Firebase("https://nfcpi.firebaseio.com/luces/sala"); fire_habitacion = new Firebase("https://nfcpi.firebaseio.com/luces/habitacion"); fire_habitacion.setValue(false); fire_sala.setValue(false); textLog = (TextView) findViewById(R.id.msgLog); textSala = (TextView) findViewById(R.id.textSala); textHabitacion = (TextView) findViewById(R.id.textHabitacion); toggleButtonSala = (ToggleButton) findViewById(R.id.tgsala); toggleButtonHabitacion = (ToggleButton) findViewById(R.id.tghabitacion); mNfcAdapter = NfcAdapter.getDefaultAdapter(this); toggleButtonSala.setEnabled(false); toggleButtonSala.setTextOff("Apagada"); toggleButtonSala.setTextOn("Encendida"); toggleButtonHabitacion.setEnabled(false); toggleButtonHabitacion.setTextOff("Apagada"); toggleButtonHabitacion.setTextOn("Encendida"); fire_sala.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { ultimoEstadoSala = ! (Boolean) dataSnapshot.getValue(); toggleButtonSala.setChecked(!ultimoEstadoSala); } @Override public void onCancelled(FirebaseError firebaseError) { } }); fire_habitacion.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { ultimoEstadoHabitacion = ! (Boolean) dataSnapshot.getValue(); toggleButtonHabitacion.setChecked(!ultimoEstadoHabitacion); } @Override public void onCancelled(FirebaseError firebaseError) { } }); if (mNfcAdapter == null) { Toast.makeText(this, "Este dispositivo no soporta NFC.", Toast.LENGTH_LONG).show(); finish(); return; } if (!mNfcAdapter.isEnabled()) { textLog.setText("NFC desactivdado"); } else { textLog.setText("NFC activado"); } handleIntent(getIntent()); } @Override protected void onResume() { super.onResume(); setupForegroundDispatch(this, mNfcAdapter); } @Override protected void onPause() { stopForegroundDispatch(this, mNfcAdapter); super.onPause(); } @Override protected void onNewIntent(Intent intent) { handleIntent(intent); } private void handleIntent(Intent intent) { String action = intent.getAction(); if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) { String type = intent.getType(); if (MIME_TEXT_PLAIN.equals(type)) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); new NdefReaderTask().execute(tag); } else { Log.d(TAG, "Wrong mime type: " + type); } } else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) { // In case we would still use the Tech Discovered Intent Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); String[] techList = tag.getTechList(); String searchedTech = Ndef.class.getName(); for (String tech : techList) { if (searchedTech.equals(tech)) { new NdefReaderTask().execute(tag); break; } } } } /* @param activity The corresponding {@link Activity} requesting the foreground dispatch. * @param adapter The {@link NfcAdapter} used for the foreground dispatch. */ public static void setupForegroundDispatch(final MainActivity activity, NfcAdapter adapter) { final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass()); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0); IntentFilter[] filters = new IntentFilter[1]; String[][] techList = new String[][]{}; // Notice that this is the same filter as in our manifest. filters[0] = new IntentFilter(); filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED); filters[0].addCategory(Intent.CATEGORY_DEFAULT); try { filters[0].addDataType(MIME_TEXT_PLAIN); } catch (IntentFilter.MalformedMimeTypeException e) { throw new RuntimeException("Check your mime type."); } adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList); } /** @param activity The corresponding {@linkBaseActivity} requesting to stop the foreground dispatch. * @param adapter The {@link NfcAdapter} used for the foreground dispatch. */ public static void stopForegroundDispatch(final MainActivity activity, NfcAdapter adapter) { adapter.disableForegroundDispatch(activity); } /** Background task for reading the data. Do not block the UI thread while reading. * * @author Ralf Wondratschek * */ private class NdefReaderTask extends AsyncTask{ @Override protected String doInBackground(Tag... params) { Tag tag = params[0]; Ndef ndef = Ndef.get(tag); if (ndef == null) { // NDEF is not supported by this Tag. return null; } NdefMessage ndefMessage = ndef.getCachedNdefMessage(); NdefRecord[] records = ndefMessage.getRecords(); for (NdefRecord ndefRecord : records) { if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN && Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { try { return readText(ndefRecord); } catch (UnsupportedEncodingException e) { Log.e(TAG, "Unsupported Encoding", e); } } } return null; } private String readText(NdefRecord record) throws UnsupportedEncodingException { /** See NFC forum specification for "Text Record Type Definition" at 3.2.1 * * http://www.nfc-forum.org/specs/ * * bit_7 defines encoding * bit_6 reserved for future use, must be 0 * bit_5..0 length of IANA language code */ byte[] payload = record.getPayload(); // Get the Text Encoding String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Language Code int languageCodeLength = payload[0] & 0063; // String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII"); // e.g. "en" // Get the Text return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding); } @Override protected void onPostExecute(String result) { if (result != null) { textLog.setText("Mensaje NDEF: " + result); if (result.equals("sala")){ Log.d("Sala: ", ultimoEstadoSala.toString()); fire_sala.setValue(ultimoEstadoSala); } if(result.equals("habitacion")){ Log.d("Habitación: ", ultimoEstadoHabitacion.toString()); fire_habitacion.setValue(ultimoEstadoHabitacion); } } } } }
3. Instalando lo necesario en Raspbian
sudo apt-get update sudo apt-get install python-dev sudo apt-get install python-gpiozero sudo wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py sudo pip install requests==1.1.0 sudo pip install python-firebase
4. Código Python (Raspberry Pi)
Los archivo principales del proyecto son el main.py, que es el archivo principal y Conexion.py, es una clase que se encarga de comunicarse con Firebase
main.py
#!/usr/bin/python # -*- coding: utf-8 -*- #Autor: Jefferson Rivera #Email: riverajefer@gmail.com import sys import signal from gpiozero import LED from clases.Conexion import Conexion led_sala = LED(17) led_habitacion = LED(27) def procesa(value_sala, value_habitacion): if value_sala: led_sala.on() print "Encendido Sala" else: led_sala.off() print "Apagado Sala" if value_habitacion: led_habitacion.on() print "Encendido Habitación" else: led_habitacion.off() print "Apagado Habitación" sys.stdout.flush() try: print "Inicio" t = Conexion(procesa) t.daemon=True t.start() signal.pause() except (KeyboardInterrupt, SystemExit): raise print "Salida"
clases/Conexion.py
Esta clase es la encargada de establecer la comunicación con Firebase, y enviar los datos apropiados al archivo main.py, para que este controle el GPIO
from firebase import firebase import threading import time class Conexion(threading.Thread): def __init__(self, retorno): threading.Thread.__init__(self) self.retorno = retorno self.fire = firebase.FirebaseApplication('https://nfcpi.firebaseio.com/', None) self.ultimo_estado_sala = self.fire.get('/luces/sala', None) self.ultimo_estado_habitacion = self.fire.get('/luces/habitacion', None) self.retorno(self.ultimo_estado_sala, self.ultimo_estado_habitacion) def run(self): ES = [] ES.append(self.ultimo_estado_sala) EH = [] EH.append(self.ultimo_estado_habitacion) i = 0 while True: estado_actual_sala = self.fire.get('/luces/sala', None) ES.append(estado_actual_sala) estado_actual_habitacion = self.fire.get('/luces/habitacion', None) EH.append(estado_actual_habitacion) if ES[i] != ES[-1]: self.retorno(estado_actual_sala, estado_actual_habitacion) del ES[0] if EH[i] != EH[-1]: self.retorno(estado_actual_sala, estado_actual_habitacion) del EH[0] i = i+i time.sleep(0.3)
5. Montar el siguiente circuito
Aca estoy usando mi URL, pero recomiendo que mejor usen su propia URL de Firebase, y no se olviden cambiar la referencia en en el main.java y en Conexion.py
Esos es todo lo que tienen que hacer, no es necesario crear las subrutas en firebase, eso lo hace automáticamente java

DESCARGAR PROYECTO
Referencias:
https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef
http://developer.android.com/intl/es/guide/topics/connectivity/nfc/advanced-nfc.html
http://code.tutsplus.com/tutorials/reading-nfc-tags-with-android--mobile-17278
hola si no es mucha molestia me podrias indicar como hacer para que cuando arranque la raspberry se ejecute el programa
ResponderEliminaramigo buenas noches, te escribí un correo.
ResponderEliminarHola
ResponderEliminarNo hablo muy espanol.
sou brasileiro, onde achar raspberry pi barato em rivera?
tenho um raspberry pi b e pretendo ter mais um
Hola (hi) Ronaldo.
EliminarI do not understand the question
Regards
Cordialmente
Jefferson Rivera
Se pega mi raspberry cuando intento instalar firebas admin
ResponderEliminar