Radio Internet Wi‑Fi con Raspberry Pi y Arduino: Emisoras globales en streaming
Componentes y suministros
| Componente | Cantidad | Notas |
|---|---|---|
| Arduino UNO | 1 | |
| Raspberry Pi 3 Model B | 1 | Wi‑Fi integrado, sin antena USB |
| SainSmart LCD Keypad Shield para Arduino | 1 | Pantalla LCD + botones |
| Fuente 5 V | 1 |
Aplicaciones y servicios en línea
- Python (en Raspberry Pi)
Sobre el proyecto
Visión general
Me encanta escuchar la radio mientras hago cosas o cocino, pero donde vivo la recepción FM es pésima. Con Internet, escuchar emisoras de todo el mundo es un placer, pero no me gusta usar el smartphone para música. Tras mucho buscar, encontré varias soluciones.
Basé este proyecto en otro tutorial: Arduino / Raspberry Pi Internet Radio de akellyirl. El código está en Python en la Raspberry Pi y usa el demonio reproductor de música de Linux (mpd) y el cliente mpc. La librería nanpy permite a Python comunicarse con el Arduino, que controla botones y LCD.
Usé un shield LCD/teclado para Arduino con botones (SainSmart LCD Keypad Shield) y luego añadí una tira de 4 botones recuperada de un despertador roto. Primero usé una Raspberry Pi 2 con adaptador Wi‑Fi USB, pero ahora uso una RPi 3 con Wi‑Fi integrado.
Lo más difícil fue encontrar las URLs correctas de las emisoras. Finalmente hallé URL HELPER, un programa que "olfatea" el sitio y muestra las URLs del multimedia en reproducción. Para el sonido usé altavoces activos de PC también recuperados.
Instrucciones de instalación (RPi 3)
Basadas en el tutorial original de akellyirl:
- Actualiza Raspbian:
$ sudo apt-get update - Instala mpd/mpc:
$ sudo apt-get install mpc mpd
Para que Python hable con Arduino, instalamos la librería nanpy para Python y el firmware nanpy para Arduino:
- Paquetes Arduino para compilar firmware nanpy:
$ apt-get install arduino - Descarga y extrae nanpy para Python (en
/home/pi):$ wget https://pypi.python.org/packages/source/n/nanpy/nanpy-v0.7.tar.gz $ tar xvf nanpy-v0.7.tar.gz - Descarga e instala
setuptools(dependencia):$ wget https://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz#md5=7df2a529a074f613b509fb44feefe74e $ tar xvf setuptools-0.6c11.tar.gz - Descarga e instala
pyserial(dependencia):$ wget https://pypi.python.org/packages/source/p/pyserial/pyserial-2.6.tar.gz $ tar xvf pyserial-2.6.tar.gz - Instala setuptools:
$ cd setuptools-0.6c11 $ sudo python setup.py install - Instala nanpy para Python:
$ cd ../nanpy $ sudo python setup.py install - Instala pyserial:
$ cd ../pyserial-2.6 $ sudo python setup.py install
Ahora subimos el firmware nanpy al Arduino.
Firmware
nanpy permite a un programa Python en la Raspberry Pi operar el Arduino con sintaxis Arduino estándar, ej.: int val = Arduino.analogRead(14).
Nanpy tiene dos componentes:
- Librería Python para comandos Arduino familiares y comunicación.
- Firmware que corre en Arduino y habla con Python en la Pi.
Ya instalamos la parte Python y descargamos la parte Arduino en la Pi. Ahora subimos el firmware al Arduino.
Conecta Arduino al USB de la Raspberry Pi.
- Sube firmware nanpy:
$ cd ../nanpy/firmware $ export BOARD=uno $ make $ make upload
Si dice que no encuentra el dispositivo en /dev/ttyACM0, prueba el otro puerto USB.
Creé un script de lista de reproducción y un script Python (en la pestaña Código) y hice que el script Python se auto-ejecute al arrancar la Raspberry. También añadí otro botón para mostrar menú (IP, salida de audio, etc.).
Actualización: Lo rehice: añadí codificadores rotativos para sintonía y volumen, e imprimí la caja en 3D:
Código
- piradio (Python)
- radio_plylist.sh (Shell)
piradio (Python)
No soy programador de Python (es mostly copy/paste de trozos encontrados en Google). Hasta ahora funciona :) Este script debe cargarse al inicio en la Pi (lo añadí a crontab).
from datetime import datetime
from subprocess import *
from time import sleep, strftime
from Queue import Queue
from threading import Thread
import os
from nanpy import Arduino, Lcd
import socket
Arduino.pinMode(14, INPUT)
lcd = Lcd([8,9,4,5,6,7],[16,2]) # Pines LCD para shield SainSmart
lcd.printString("Ruben's RadioZ",0,0)
lcd.printString("Loading" + "."*3,0,1)
sleep(5)
max_trax = 10
x = 1
loop_menu = 1
loop_radio = 1
stations = []
stations.append("Ecco 99 ")
stations.append("Galgalaz ")
stations.append("Galaz ")
stations.append("88 FM ")
stations.append("Gimel ")
stations.append("Radios 100fm ")
stations.append("Kol Hamusica ")
stations.append("WQXR New York ")
stations.append("WPR Winsconsin ")
stations.append("BBC world servic")
stations.append("LINN jazz")
stations.append("LINN classical")
def get_local_ip_address(target):
ipaddr = ''
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((target, 8000))
ipaddr = s.getsockname()[0]
s.close()
except:
pass
return ipaddr
print "Raspberry Pi - Local IP Address"
print(get_local_ip_address('10.0.1.1'))
print(get_local_ip_address('google.com'))
def display_ipaddr():
show_wlan0 = "ip addr show wlan0 | cut -d/ -f1 | awk '/inet/ {printf \"w%15.15s\", $2}'"
show_eth0 = "ip addr show eth0 | cut -d/ -f1 | awk '/inet/ {printf \"e%15.15s\", $2}'"
ipaddr = ''
ipaddr = get_local_ip_address('10.0.1.1')
lcd.printString('IP Address:',0,0)
lcd.printString(ipaddr,0,1)
sleep(2)
def displaymenu():
if x==1:
lcd.printString("1. Display ",0,0)
lcd.printString(" IP Address ",0,1)
elif x==2:
lcd.printString("2. Audio Output ",0,0)
lcd.printString(" to hdmi Port ",0,1)
elif x==3:
lcd.printString("3. Audio Output ",0,0)
lcd.printString(" to Analog port",0,1)
elif x==4:
lcd.printString("4. Audio Output ",0,0)
lcd.printString(" Auto Sel. Port",0,1)
elif x==5:
lcd.printString("5. Reload the ",0,0)
lcd.printString(" Playlist ",0,1)
elif x==6:
lcd.printString("6. ShutDown ",0,0)
lcd.printString(" the System ",0,1)
else:
lcd.printString("7. Exit to ",0,0)
lcd.printString(" Main Menu ",0,1)
def load_playlist():
output = run_cmd("mpc clear")
output = run_cmd("/home/pi/radio/radio_playlist.sh")
def run_cmd(cmd):
p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT)
output = p.communicate()[0]
return output
def getKey():
val = Arduino.analogRead(14)
if val == 1023: return "NONE"
elif val < 100: return "RIGHT"
elif val < 150: return "UP"
elif val < 330: return "DOWN"
elif val < 510: return "LEFT"
elif val < 750: return "SEL"
else: return "KBD_FAULT"
load_playlist()
def getTrack():
L = [S.strip('\n') for S in os.popen('mpc').readlines()]
output = run_cmd("mpc current")
station = output[0:16]
track = output[-17:-1]
lcd.printString(station + " "*(16 - len(station)), 0, 0)
lcd.printString(track + " "*(16 - len(track)), 0, 1)
track_num = 1
os.system("sudo service mpd restart")
os.system("mpc play " + str(track_num))
while loop_radio == 1:
getTrack()
loop_menu = 1
x = 1
key = getKey()
if key == "UP":
track_num += 1
if track_num > max_trax: track_num = 1
lcd.printString(stations[track_num-1],0,0)
os.system("sudo service mpd restart")
os.system("mpc play " + str(track_num))
getTrack()
elif key == "DOWN":
track_num -= 1
if track_num < 1: track_num = max_trax
lcd.printString(stations[track_num-1],0,0)
os.system("sudo service mpd restart")
os.system("mpc play " + str(track_num))
getTrack()
elif key == "LEFT":
os.system("mpc volume +10")
lcd.printString(16*" ", 0, 0)
lcd.printString(16*" ", 0, 1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME UP:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
elif key == "RIGHT":
os.system("mpc volume -10")
lcd.printString(16*" ",0,0)
lcd.printString(16*" ", 0,1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME DOWN:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
elif key == "SEL":
while loop_menu == 1:
displaymenu()
key = getKey()
if key == "RIGHT":
os.system("mpc volume +10")
lcd.printString(16*" ", 0, 0)
lcd.printString(16*" ", 0, 1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME UP:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
elif key == "LEFT":
os.system("mpc volume -10")
lcd.printString(16*" ",0,0)
lcd.printString(16*" ", 0,1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME DOWN:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
elif key == "UP":
if x <= 1: x = 7
else: x = x - 1
elif key == "DOWN":
if x >= 7: x = 1
else: x = x + 1
elif key == "SEL":
if x == 1:
display_ipaddr()
sleep(1)
elif x == 2:
output = run_cmd("amixer -q cset numid=3 2")
lcd.printString("Audio OUT-->HDMI", 0, 0)
lcd.printString("output ", 0, 1)
sleep(.5)
elif x == 3:
output = run_cmd("amixer -q cset numid=3 1")
lcd.printString("Audio OUT->Analog", 0, 0)
lcd.printString("output ", 0, 1)
sleep(.5)
elif x == 4:
output = run_cmd("amixer -q cset numid=3 0")
lcd.printString("Audio OUT-> Auto", 0, 0)
lcd.printString("output ", 0, 1)
sleep(.5)
elif x == 5:
load_playlist()
os.system('mpc play 1')
elif x == 6:
lcd.printString("Good Bye ", 0, 0)
lcd.printString("Have a Nice Day ", 0, 1)
output = run_cmd("mpc stop")
quit()
elif x == 7:
loop_menu = 0
getTrack()
break
elif key == "RIGHT":
os.system("mpc volume +2")
lcd.printString(16*" ",0,0)
lcd.printString(16*" ", 0,1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME UP:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
elif key == "LEFT":
os.system("mpc volume -2")
lcd.printString(16*" ", 0, 0)
lcd.printString(16*" ", 0, 1)
output = run_cmd("mpc volume")
lcd.printString("VOLUME DOWN:", 0, 0)
lcd.printString(output, 5, 1)
sleep(.25)
lcd.printString(16*" ",0,0)
lcd.printString(16*" ",0,1)
radio_plylist.sh (Shell)
Mi lista de reproducción con emisoras israelíes:
#! /bin/sh mpc clear 1>/dev/null #1 ecco99 mpc add https://99.livecdn.biz/99fm_aac #2 galgalaz mpc add https://glglzwizzlv.bynetcdn.com/glglz_mp3 #3 galaz mpc add https://glzwizzlv.bynetcdn.com/glz_mp3 #4 88 fm mpc add https://ibala.vidnt.com:8000/iba_radio-88fmM #5 gimel mpc add https://ibala.vidnt.com:8000/iba_radio-gimelM #6 radios 100 fm mpc add https://100fm.streamgates.net/Radios100Fm #7 kol hamusica mpc add https://ibala.vidnt.com:8000/iba_radio-kolmusicaM #8 wqxr mpc add https://stream.wqxr.org/wqxr #9 npr current mpc add https://current.stream.publicradio.org/kcmp.mp3 #10 bbc mpc add https://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-eieuk #11 linn jazz mpc add https://radio.linnrecords.com:8003/autodj #12 linn classical mpc add https://radio.linnrecords.com:8004/autodj
Esquemáticos
Proceso de manufactura
- Construya un Mando Universal Profesional para Raspberry Pi con LIRC
- Conversión de RF a CC con Raspberry Pi: Construcción y Solución de Problemas de un Detector de Envolvente
- Cycle Chaser: Transforme su Bici en un Espectáculo de Luces Nocturno con Raspberry Pi
- Construya un Detector de Ladrones Basado en Raspberry Pi – Guía Paso a Paso
- Monitor de temperatura casero con Raspberry Pi, MCP9808, InfluxDB y Grafana
- Construye sistema domótico con Raspberry Pi para control remoto
- MrRobot: Robot Rapiro controlado por móvil Ubuntu con voz, tacto e interacción por movimiento
- Robot DIY inspirado en Wall‑E con Raspberry Pi y caja de CD
- Construya un robot Raspberry Pi controlado por Bluetooth con retroalimentación de audio
- Construya un robot con streaming de vídeo controlado por Internet con Arduino y Raspberry Pi
- Placa RasPiRobot Board V2: Convierte tu Raspberry Pi en un Controlador de Robot Potente