Raspberry Pi Cero conectada a pantalla de información


Raspberry Pi Zero es un nuevo dispositivo que entra fuerte en el terreno de los dispositivos conectados y a la Internet de las Cosas. Gracias a su reducido tamaño y consumo podemos darle un montón de posibilidades en casa, como por ejemplo la automatización de determinadas tareas o simplemente mostrar información en un espacio ínfimo. Especialmente si la complementamos con unpequeño display OLED como éste, comercializado por Adafruit.

Frederic Vandenbosch ha creado un interesante proyecto con la Raspberry Pi Zero, usando un  display de Adafruit anteriormente mencionado y un par de pulsadores soldados en los terminales GPIO de la Raspberry Pi.

Para conectar la Zero a internet, Frederic ha utilizado  una extensión wifi de la que ya hablamos en este blog   y que permite agregar conectividad Wi-Fi a la menor de las Raspberry Pi soldándolo directamente a la placa. Como podéis ver en el vídeo que acompaña la imagen, los dos pulsadores son programables y en los ejemplos propuestos permiten navegar por una serie de opciones, como por ejemplo mostrar la dirección IP o forzar la reconexión de la Raspberry Pi Zero a internet.

 

 

Hardware

El hardware consiste en los siguientes componentes:

  • Raspberry Pi Cero
  • Adafruit 128 × 64 SSD1306 OLED
  • Edimax wifi dongle
  • 2 grandes pulsadores

El cableado del OLED y botones es bastante sencillo, como se ilustra a continuación:

adafrut

El dongle wifi se conecta de la misma manera como lo hice anteriormente con el hub USB:

  • Pi Zero PP1 a dongle 5V
  • Pi Cero PP6 al dongle GND
  • Pi Cero PP22 para dongle D +
  • Pi Cero PP23 para dongle D-

Por último, para mantener todo en su lugar, he diseñado una caja sencilla lo suficientemente grande para encajar todo. Un panel trasero se atornilla en el lugar para mantener todos los componentes en el interior, dejando al descubierto el puerto microUSB entrada de energía en el lado.

 

Un poco de cinta kapton evita contactos expuesto a tocarse y mantiene el cableado en su lugar. El dongle wifi se coloca en la parte superior para una mejor conectividad. Su LED azul brillante brilla a través del recinto, dando una clara indicación de su estado y la actividad.

Los archivos para el recinto de impresión 3D se pueden encontrar en Thingiverse: http://www.thingiverse.com/thing:1193350

Software

Por el lado del software del proyecto, se necesita la creación de la tarjeta microSD con la última imagen Raspbian Jessie disponible.Arrancando  desde el combo hub Pi Cero / USB con el teclado y wifi dongle conectado  porque el puerto USB de este proyecto Pi Cero se ha cableado a un dongle wifi y un teclado ya no se puede conectar .

Se configura el wifi añadiendo el SSID y la frase de contraseña correcta en el archivo / etc / network / interfaces. Después de probar la conectividad wifi, poner la tarjeta microSD de vuelta en el Pi correcta. Con la conectividad de red, es posible iniciar sesión con SSH y trabajar en el guión para mostrar la información deseada.

Uso de la Biblioteca de Python Adafruit OLED SSD1306 y algo de código Python personalizada, en el ejemplo se programan  tres pantallas diferentes:

  • Hora y fecha
  • Configuración de la red
  • Los medios sociales suscriptores / seguidores

El botón izquierdo a través de las diferentes pantallas, mientras que el botón derecho desencadena una acción personalizada por pantalla.

En el caso de la visualización de la hora y la fecha, el botón, cambia entre las 12h y las 24h representación. Para la configuración de red, obliga al wifi de volver a conectar mediante un descenso de la interfaz y obligando de nuevo. Por último, para evitar el tráfico excesivo, información de medios sociales solamente se recupera cada cinco minutos, al pulsar el botón de fuerza a la recuperación de la información.

Por supuesto, esto es sólo un subconjunto de lo que podría ser mostrado. Podría recuperar la información del tiempo, el correo electrónico, últimos tweets, etc … Usted también podría tener que desplazarse por pantallas diferentes sin necesidad de pulsar un botón. Todo es posible.

El código actual se puede encontrar a continuación. Está lejos de ser perfecto, pero hace el trabajo.

Por último, para conseguir que se inicie automáticamente al arrancar el sistema, cree un script lanzador (por ejemplo, «launcher.sh«) que contiene la ruta de acceso a la secuencia de comandos, así:

  #! / bin / sh
 cd / home / pi
 sudo python info_display.py y

Y por último, añadir el cronjob con el comando «sudo crontab -e«:

  reboot sh /home/pi/launcher.sh

Cada vez que el Pi se inicia, se pondrá en marcha el script.

#!/usr/bin/env python
import time
import Adafruit_SSD1306
import RPi.GPIO as GPIO
import Image
import ImageFont
import ImageDraw
import os
def display_time():
# Collect current time and date
if(time_format):
current_time = time.strftime(«%I:%M«)
else:
current_time = time.strftime(«%H:%M«)
current_date = time.strftime(«%d/%m/%Y«)
# Clear image buffer by drawing a black filled box
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 35)
# Position time
x_pos = (disp.width/2)/2)
y_pos = 2 + (disp.height48)/2 (35/2)
# Draw time
draw.text((x_pos, y_pos), current_time, font=font, fill=255)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 8)
# Position date
x_pos = (disp.width/2)(string_width(font,current_date)/2)
y_pos = disp.height10
# Draw date
draw.text((x_pos, y_pos), current_date, font=font, fill=255)
# Draw the image buffer
disp.image(image)
disp.display()
def display_social():
# Collect social media subscribers/followers/… by parsing webpages
twitter = os.popen(«curl https://twitter.com/f_vdbosch?lang=en | grep ‘data-nav=followers‘ | grep -o ‘[0-9]\+’«).read()
youtube = os.popen(«curl https://www.youtube.com/c/FrederickVandenbosch | grep -o ‘[0-9]\+ subscribers’ | grep -o ‘[0-9]\+’«).read()
facebook = «0«
instagram = os.popen(«curl https://www.instagram.com/f_vdbosch/ | grep -o ‘followed_by:{count:[0-9]\+}’ | grep -o ‘[0-9]\+’«).read()
googleplus = «0«
# Put data in lists that can be iterated over
channels = [«YouTube«, «Twitter«, «Facebook«, «Instagram«, «Google+«]
subscribers = [youtube, twitter, facebook, instagram, googleplus]
# Clear image buffer by drawing a black filled box
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 8)
# Iterate over lists
for i in range(0, 5):
# Position channel name
x_pos = 2
y_pos = 2 + (((disp.height4)/5)*i)
# Draw channel name
draw.text((x_pos, y_pos), channels[i], font=font, fill=255)
# Position subcribers/followers/…
x_pos = disp.width 2 string_width(font, subscribers[i])
y_pos = 2 + (((disp.height4)/5)*i)
# Draw subcribers/followers/…
draw.text((x_pos, y_pos), subscribers[i], font=font, fill=255)
# Draw the image buffer
disp.image(image)
disp.display()
def display_network():
# Collect network information by parsing command line outputs
ipaddress = os.popen(«ifconfig wlan0 | grep ‘inet addr’ | awk -F: ‘{print $2}’ | awk ‘{print $1}’«).read()
netmask = os.popen(«ifconfig wlan0 | grep ‘Mask’ | awk -F: ‘{print $4}’«).read()
gateway = os.popen(«route -n | grep ‘^0.0.0.0’ | awk ‘{print $2}’«).read()
ssid = os.popen(«iwconfig wlan0 | grep ‘ESSID’ | awk ‘{print $4}’ | awk -F\\ ‘{print $2}’«).read()
# Clear image buffer by drawing a black filled box
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 12)
# Position SSID
x_pos = 2
y_pos = 2
# Draw SSID
draw.text((x_pos, y_pos), ssid, font=font, fill=255)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 8)
# Position IP
y_pos += 12 + 10
# Draw IP
draw.text((x_pos, y_pos), «IP: «+ipaddress, font=font, fill=255)
# Position NM
y_pos += 10
# Draw NM
draw.text((x_pos, y_pos), «NM: «+netmask, font=font, fill=255)
# Position GW
y_pos += 10
# Draw GW
draw.text((x_pos, y_pos), «GW: «+gateway, font=font, fill=255)
# Draw the image buffer
disp.image(image)
disp.display()
def display_custom(text):
# Clear image buffer by drawing a black filled box
draw.rectangle((0,0,width,height), outline=0, fill=0)
# Set font type and size
font = ImageFont.truetype(Minecraftia.ttf, 8)
# Position SSID
x_pos = (width/2) (string_width(font,text)/2)
y_pos = (height/2) (8/2)
# Draw SSID
draw.text((x_pos, y_pos), text, font=font, fill=255)
# Draw the image buffer
disp.image(image)
disp.display()
def string_width(fontType,string):
string_width = 0
for i, c in enumerate(string):
char_width, char_height = draw.textsize(c, font=fontType)
string_width += char_width
return string_width
# Set up GPIO with internal pull-up
GPIO.setmode(GPIO.BCM)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# 128×64 display with hardware I2C
disp = Adafruit_SSD1306.SSD1306_128_64(rst=24)
# Initialize library
disp.begin()
# Get display width and height
width = disp.width
height = disp.height
# Clear display
disp.clear()
disp.display()
# Create image buffer with mode ‘1’ for 1-bit color
image = Image.new(1, (width, height))
# Load default font
font = ImageFont.load_default()
# Create drawing object
draw = ImageDraw.Draw(image)
prev_millis = 0
prev_social = 0
display = 0
time_format = True
while True:
millis = int(round(time.time() * 1000))
# Software debouncing
if((millis prev_millis) > 250):
# Cycle through different displays
if(not GPIO.input(12)):
display += 1
if(display > 2):
display = 0
prev_millis = int(round(time.time() * 1000))
# Trigger action based on current display
elif(not GPIO.input(16)):
if(display == 0):
# Toggle between 12/24h format
time_format = not time_format
time.sleep(0.01)
elif(display == 1):
# Reconnect to network
display_custom(«reconnecting wifi …«)
os.popen(«sudo ifdown wlan0; sleep 5; sudo ifup –force wlan0«)
time.sleep(0.01)
elif(display == 2):
# Refresh social media now
display_custom(«fetching data …«)
display_social()
time.sleep(0.01)
prev_millis = int(round(time.time() * 1000))
if(display == 0):
display_time()
prev_social = 0
elif(display == 1):
display_network()
prev_social = 0
elif(display == 2):
# Only fetch social media data every 5 minutes when active
if((millis prev_social) > 300000):
display_custom(«fetching data …«)
display_social()
prev_social = millis
time.sleep(0.1)

 

El uso de una pantalla OLED Adafruit, dos pulsadores, un dongle wifi y un pi Cero, permite como vemos  una pantalla de información conectada a internet. La información podría ser cualquier cosa: fecha y hora, el clima, el estado de las redes sociales, etc … Los dos botones se utilizan para desplazarse por los datos y desencadenar ciertas acciones.
Sin duda el abanico de posibilidades es inmenso..

Envio de correo SMTP desde Netduino


Todos sabemos, que Micro Framework no puede tener todas las características de .NET Framework completo. Una cosa que  faltaba es SmtpClient clase que permita el envío de mensajes de correo electrónico utilizandoSimple Mail Transfer Protocol (SMTP). Si nos fijamos en la especificación SMTP encontrará protocolo comuinication muy fácil – es sólo comandos de texto. Comando no, la respuesta Atrás – eso es todo.

Asi  es de fácil puede ser el envío de e-mails de .NET Micro Framework pero  no lamntablemente esta clase no esta disponible para , Net Micro Framework 

 utilizando (SmtpClient smtp = new SmtpClient ("smtp.hostname.net", 25))
 {
     // Enviar mensaje
     smtp.Send ("[email protected]",
               "[email protected]",
               "Buenas noticias",
               "¿Cómo te Foo?");
 }

Esto le  trajo  la idea a Pavel Bánský  de escribir  su propia implementación de la clase SmtpClient para .NET Micro Framework   que ademas  ha decididoser lo más compatible posible con la versión de «escritorio» de System.Net.Mail.SmtpClient clase.

1920px-par_avion_air_mail
«Par avion air mail» by Kristoferb at English Wikipedia. Licensed under CC BY-SA 3.0 via Commons.

 

 

 

Bansky.SPOT.Mail biblioteca de clases

Enviar sencilla correo electrónico mediante SMTP es muy fácil; PERO. Hoy en día la mayor parte del servidor SMTP requiere autenticación. Esto significa, que SmtpClient sin autenticación sería un poco inútil.

En el caso de usar el servidor de correo de terra

SMTP: smtp.terra.com

Puerto 587 o 465 (SSL)

Pero  atención   , no podra usar SSL, por  lo que no olvide  apuntar el puerto 587

Y aquí comienza la diversión. Autenticación SMTP necesita Base64 nombre de usuario y la contraseña codificada. Damned, Base64 no es compatible con Micro Framework. Por lo tanto, la primera tarea es obtener Base64 clase de codificación / decodificación. Una vez que usted pueda codificar datos en Base64, puede codificar los datos de los archivos adjuntos de correo electrónico también. Vamos a implementar System.Net.Mail.Attachment clase. Más funcionalidad necesita el manejo de excepciones más compleja. Ok, agreguela clase  System.Net.Mail.SmtpException .

Después de unos días te despiertas y ves, que ha terminado con la biblioteca de clases completa para el correo electrónico. Eso es cómo se  creo biblioteca de clases Bansky.SPOT.Mail 

Base 64, Autenticación y error en Micro Framework

Cuando el servidor SMTP requiere autenticación, el cliente de sesión de inicio con el comando EHLO domain.com.Servidor responde con métodos compatibles de autenticación. Simplemente dicho, los métodos de las credenciales de codificación. La mayoría de los servidores SMTP soporta método SENCILLOS o entrada o ambos; si no, SmtpClientva a terminar con una excepción. Hay otros métodos de autenticación como CRAM-MD5 y CRAM-SHA1.

Información de autenticación para el método SENCILLOS es esta cadena «usernamepassword» codificado en Base64. El problema es que Micro Framework versión 2.5 (y menos) interpreta «» como un fin de la cadena. Esto significa que la cadena de autenticación SENCILLOS se interpreta como una cadena vacía. Caracteres  después de  «» se ignoran pero esto se puede. En primer lugar debe conviertir  en  serie de «contraseña de usuario» en la matriz de bytes y luego reemplazar los espacios adecuados con el byte 0x00. Tal matriz de bytes es la entrada para el método Base64.Encode ().

Es importante decir que el núcleo de la clase Base 64 se basa en Base64Encoder clase de Timm Martin  y se  he añadido los métodos para dividir los datos codificados en líneas de 76 bytes como es requerido por MIME especificación.

Siguiente código muestra cómo configurar las credenciales de autenticación a clase SmtpClient. Método de autenticación será elegido automáticamente en función de las capacidades del servidor.

 utilizando (SmtpClient smtp = new SmtpClient ("smtp.hostname.net", 25))
 {
     // Crear un mensaje
     MailMessage mensaje = new MailMessage ("[email protected]",
                                           "[email protected]",
                                           "Buenas noticias",
                                           "¿Cómo te Foo?");

     // Authenicate al servidor
     smtp.Authenticate = true;
     smtp.Username = "UserLogin";
     smtp.Password = "userpassword";

     // Enviar mensaje
     smtp.Send (mensaje);
 }

Archivos adjuntos de correo electrónico

Además de los mensajes HTML con formato, la implementación MailMessage soporta archivos adjuntos. Archivo adjunto de e-mail puede ser cualquier dato binario, que se procesan utilizando la codificación Base64 y agregados en mensaje MIME multiparte. Ejemplo de mensaje con archivo adjunto está por debajo.

ADVERTENCIA: codificación de datos binarios en base64 en .NET Micro Framework puede ser extremadamente tiempo y consumo de recursos. Esto significa, que el mayor de los datos es, más tiempo se necesita para procesarla; y si se dice  «más tiempo», es porque  es  realmente mucho tiempo. Por lo tanto, tener cuidado y no se sorprenda.

 MailMessage mensaje = new MailMessage ();
 // Establecer el nombre del remitente y dirección
 message.From = new MailAddress ("[email protected]", "Foo Bar");

 // Destinatarios Set
 message.To.Add (nueva MailAddress ("[email protected]", "John Doe"));
 message.Cc.Add (nueva MailAddress ("[email protected]"));

 message.Subject = "Hola Mundo";
 message.Body = "de ahora en adelante usted puede enviar mensajes de correo electrónico desde <b> .NET Micro Framework </ b>.";
 // Cuerpo Formato como HTML
 message.IsBodyHtml = true;

 // Crear nuevo adjunto y definir su nombre
 Accesorio = nuevo Adjunto ("Snwoflake.gif");        
 attachment.ContentType = "image / gif";
 attachment.TransferEncoding = TransferEncoding.Base64;
 // Contenidos adjuntos
 attachment.Content = Base64.Encode (Resources.GetBytes (
                                     Resources.BinaryResources.Snowflake_gif),
                                     true);

 // Añadir adjunto al mensaje
 message.Attachments.Add (archivo adjunto);

 // Crear instancia SMTP nueva
 SmtpClient smtp = new SmtpClient ("smtp.contoso.com", 25);
 probar
 {
     // Authenicate al servidor
     smtp.Authenticate = true;
     smtp.Username = "UserLogin";
     smtp.Password = "userpassword";

     // Enviar mensaje
     smtp.Send (mensaje);
 }
 capturas (SmtpException e)
 {
     // El manejo de excepciones aquí
     Debug.Print (e.Message);
     Debug.Print ("Código de error:" + e.ErrorCode.ToString ());
 }
 finalmente
 {
     smtp.Dispose ();
 }

Cabeceras adicionales

Cada mensaje de correo contiene cabecera, que especifica la información como la fecha en que se creó el mensaje, el nombre del remitente, etc. Si usted quiere poner información adicional en la cabecera se puede utilizar la propiedadencabezados. Consulte el siguiente ejemplo.

 MailMessage mensaje = new MailMessage ("[email protected]",
                                       "[email protected]",
                                       "Buenas noticias",
                                       "¿Cómo te Foo?");

 message.Headers = "X-Priority: 1 
  ";
 message.Headers + = "X-Microsoft Mail-Prioridad: Alta 
  ";
 message.Headers + = "X-Mailer: Micro Framework mail del remitente 
  ";

Manejo de excepciones

Además excepciones estándar como ArgumentNullException y ArgumentOutOfRangeException, también haySmtpException lanzada por Enviar método de SmtpClient. SmtpException en marco completo contiene propiedadStatusCode, que describe el estado en que se produjo la excepción. Desde mi Enviar método no es tan rico, he reemplazado StatusCode con ErrorCode, que describe la razón de la excepción. La enumeración SmtpErrorCodecontiene valores como BarResponse, AuthFailed, connectionFailed y así sucesivamente.

Demostración y Descarga

Biblioteca completa con las fuentes, documentación y aplicación de la muestra están disponibles para su descarga.Biblioteca fue probado en emulador y Maestro GHI Embedded módulo. Todo el código    el autor  ha  movido el   software al repositorio GitHub.

 

 

 

Fuente