Pourquoi fabriquer son propre radio-réveil ?
Vous en avez marre de votre vieux radio réveil qui n’arrive plus à capter la FM et a un bruit de sonnerie infernal ?
Vous aimeriez un radio réveil qui puisse capter la radio FM via internet : de bien meilleur qualité audio et qui puisse avoir une sonnerie de votre choix ?
Vous pourriez utiliser votre téléphone mais il faut penser à couper toutes ces notifications dont vous avez besoin en journée qui le font vibrer la nuit inutilement.
Pourquoi utiliser un raspberry Pi ?
Alors pourquoi ne pas utiliser un Raspberry Pi ? Voilà ce que je me suis dit il y a quelques temps.
On pourrait tenter de le faire avec un arduino ou un ESP32. Mais il faut quand même pouvoir lire du son en streaming ou une liste de fichiers mp3 dans une thread distincte : un Arduino n’est pas assez puissant pour ça. Et l’ESP32 sera limite.
De quoi aurions nous besoin ?
On peut tout imaginer comme options possibles.
Mais partons de la base. Il faut à minima :
- Afficher l’heure (donc la connaitre)
- Disposer d’un petit écran
- Lire un fichier mp3 (ou une liste de fichiers mp3)
- Avoir une sortie son
- Lire une source de streaming audio (Web radio FM)
- Avoir des boutons de réglage
- On pourrait aussi afficher la température ambiante, le taux d’humidité ambiante et tout un tas de choses amusantes.
Le choix de l’écran
On ne va pas utiliser un moniteur de PC ! Donc je suis parti sur un petit écran OLED qui possède déjà plusieurs (3 + 1 multi-positions) la présence des boutons intégrés à l’écran va grandement diminuer les câblages nécessaires.
Le waveshare 1.44 inch Oled a une résolution de 128×128 et l’avantage d’intégrer 4 boutons. Mais comme tous les écrans de type « Hat », il a l’inconvénient d’occuper toutes les broches du GPIO mêmes celles dont il n’a pas besoin. Aussi, pour utiliser d’autres broches du GPIO, il faut prévoir un HAT dérivateur. | |
Ce type de HAT, posé entre le raspberry et l’écran peut servir pour pouvoir utiliser les pin du GPIO en plus de l’écran. Sinon, seul l’écran pourra être connecté |
La mesure du temps
Contrairement à un radio-réveil classique ou un PC : Le Raspberry ne comporte pas d’horloge interne : il récupère l’heure par internet puis décompte le temps qui passe. Donc soit :
- Vous utilisez ajouter une horloge RTC : comme il faudra la connecter au GPIO , il faudra utiliser le dérivateur de GPIO , en ce cas, il devient disponible pour d’autres sondes comme par exemple : la mesure de la température.
- Soit vous faites confiance à sa connexion à internet et vous pouvez vous passer de l’horloge RTC et possiblement du dérivateur. Remarque : le tout dernier modèle de Raspberry Pi (le 5) possède une horloge RTC, ce peut-être une option.
1ers essais
Au départ, je souhaitais avoir la mesure de la température de la pièce, du taux d’humidité et avoir une horloge RTC. J’ai donc installé un dérivateur de port. Tout fonctionnait très bien mais évidement l’ensemble n’était pas très esthétique et nécessiterait un boitier. N’étant pas familier de l’impression 3D, j’ai décidé finalement de l’horloge, de la sonde de température et donc du dérivateur.
Information importante :
Dans la version de l’écran que j’ai choisis, le constructeur avait utiliser comme Pin de contrôle de la luminosité, le 24, et conseillait l’utilisation de PWM pour régler la luminosité. Hors, le Pin 24 du Raspberry n’est pas sur un canal de PWM hardware, seul un PWM software était possible. Soucis : le PWM software provoque des « flashs » intermittents.
Waveshare a donc sorti une nouvelle version avec le PIN de gestion de la luminosité sur le GPIO18 du Raspberry (qui lui est sur un canal PWM hardware).
Je vous conseille donc d’acheter cette nouvelle version (il faut consulter les caractéristiques sur le site de Waveshare et vérifier que le PIN « BL » est bien le 18 et non le 24). Mais, si vous l’achetez, vous devrez regarder mes fichiers LCD_Config.py et LCD_1in44.py pour changer le numéro de PIN du BL de 24 vers 18.
Choix final du matériel :
- Un Raspberry Pi2 ou 3 ou 4 ou 5 ou même un Pi Zéro (n’importe lequel fera l’affaire)
- L’écran Oled de chez Waveshare
- Un boitier : plusieurs solutions sont possibles, j’ai choisis un refroidisseur passif : le Pi2 est pris en sandwich entre 2 plaques de metal équipées d’ailettes de refroidissement et l’écran se pose au-dessus grâce à un petit prolongateur de GPIO.
Le boitier du Pi2 (compatible Pi3) est un sandwich de 2 plaques de métal équipées d’ailettes. | |
Le boitier éloigne l’accès au port GPIO, j’ai utilisé ce petit prolongateur de 2 rangées de 20 PINS femelles – mâles |
La programmation :
Qui dit utilisation d’un Raspberry et destination grand public dit : Python bien sûr
Donc je suis parti de la dernière distribution de Raspi OS (actuellement Bookworm) en version light (sans le bureau car je n’en ai pas besoin mais vous pouvez le laisser et choisir la version « normale », le Pi consommera juste du CPU pour rien)
Qui dit distribution récente de Linux dit aussi Python 3. Car python 2 est abandonné et il n’est presque plus utilisé.
Comme tous les langages de programmation, pour communiquer avec des différents éléments extérieur au Pi (ou au PC) on a 2 possibilités
- tout faire soit même en réinventant la roue.
- ou utiliser des bibliothèques pour les tâches spécifiques (ex ici : le pilotage de l’écran et des boutons)
L’écran m’a été fournis avec une carte de visite comportant un lien , il utilise le port SPI qu’il faudra activer grâce à l’utilitaire « raspi-config« .
Le lien concerne le wiki de l’écran, y sont expliqués comment il fonctionne, quelles bibliothèques installer pour pouvoir l’utiliser et des exemples de code d’utilisation ainsi que des scripts pour tester l’écran et les boutons.
Pour ceux que cela intéresse voici les 14 pin qu’utilise l’écran (il n’utilise donc pas les 40 Pins)
- Pour le port SPI :
- RST= 27
- DC = 25
- CS = 8
- BL = 24 !!! (18 sur les nouvelles version de l’écran)
- Pour le bouton de gauche qui a 5 fonctions : haut, bas, gauche, droite et presser :
- UP = 6, DOWN = 19
- LEFT = 5
- RIGHT = 26
- PRESS = 13
- Pour les 3 boutons de droites :
- KEY1 = 21
- KEY2 = 20
- KEY3 = 16
- Plus
- une masse
- et un +3,3V
On peut même forcer Raspi OS pour qu’il utilise cet écran comme moniteur mais je le déconseille : que faire d’un bureau sur un écran de 128×128 ?
Installation des bibliothèques pour python3
sudo apt-get update sudo apt-get install python3-pip sudo apt-get install python3-numpy sudo pip3 install RPi.GPIO sudo pip3 install spidev
Vous avez reconnu plusieurs commandes : apt (apt-get) permet de télécharger et d’installer des logiciels. Parmi ceux qui sont nécessaires, il y a « Pip » qui est l’outil indispensable pour installer des librairies complémentaires à Python et NumPy qui est une bibliothèque réalisée en C, compilée et qui fourni à Python des capacités de calculs mathématiques améliorés.
Enfin il y a Rpi.GPIO qui permet à python d’exploiter le port GPIO auquel est connecté l’écran et spidev qui permet d’utiliser le protocole SPI que l’écran exploite.
Téléchargement et tests de l’écran
sudo apt-get install p7zip-full -y wget https://files.waveshare.com/upload/f/fa/1.44inch-LCD-HAT-Code.7z 7z x 1.44inch-LCD-HAT-Code.7z sudo chmod 777 -R 1.44inch-LCD-HAT-Code cd 1.44inch-LCD-HAT-Code/RaspberryPi/
Maintenant dans 1.44inch-LCD-HAT-Code/RaspberryPi/, vous devez avoir:
- Un dossier nommé C qui contient des codes sources en C qu’on ne va pas utiliser
- Un dossier nommé python qui contient les codes en Python
Dans le dossier python on a :
- un script pour tester l’affichage de l’écran : sudo python main.py
- un script pour tester les boutons : sudo python key_demo.py
- un script de bibliothèque nommé LCD_1in44.py : il sait initialiser l’écran, l’effacer et lui demander d’afficher une image, c’est tout !
- un script de bibliothèque nommé LCD_config.py utilisé par LCD_1in44.py qui est de plus pas niveau encore : il initialise l’écran et lui envoie des données bits à bits.
Les fonctionnalités désirées :
Je souhaite que mon « Pi radio-réveil puisse » :
- Afficher l’heure qu’il est
- Afficher le jour qu’il est
- Se mettre tout seul à l’heure
- Me permettre de choisir l’heure à laquelle je veux être réveillé et afficher l’heure du réveil
- Activer – désactiver le réveil, me permettant de visualiser si l’alarme est mise ou non
- Choisir si je veux être réveillé par une sonnerie ou par la radio ou par l’écoute de titres que je possède
- Choisir la sonnerie entre différents sons possibles
- Choisir la station de radio qui me réveille
- Choisir le titre ou une liste de titre à écouter durant mon réveil
- Lancer moi-même à tout instant l’écoute d’une radio ou d’u mp3 ou d’une liste de mp3
- Stopper l’écoute que ce soit au réveil ou pas.
- Stopper l’écoute à tout moment sans être obligé d’attendre la fin du morceau
- Adoucissement de la luminosité de nuit.
Ca fait pas mal non ? D’autant que je le rappelle : la bibliothèque fournie ne sait faire que 2 choses : effacer l’écran ou lui demander d’afficher une image ! Bref toute information à afficher doit être dans une image. Donc en fait, il faut construire l’image puis l’envoyer à l’écran. Et voilà on va avoir besoin de la bibliothèque python Pillow (Pil) dont c’est justement la spécialité et c’est pour cela qu’elle est utilisée dans les scripts d’exemples fournis !
Etant donné que créer une nouvelle image et l’envoyer à l’écran prend du temps, on ne le fera que lorsque cela est nécessaire ! (Ex : on vient de passer de 12h11 à 12h12 ou un utilisateur a appuyé sur un bouton).
La lecture de sons :
Pendant la lecture du son (sonnerie ou radio, ou fichier mp3), le réveil doit continuer de répondre à l’utilisateur (afficher le changement d’heure (ex si on passe de 13h01 à 13h02) et réagir aux pressions sur les boutons. Donc la lecture de fichiers audio doit se faire dans un autre processus que le traitement de l’écran et des boutons.
En fait, j’ai choisis de faire simple : le programme du réveil lancera un sous-programme en récupérant son identifiant ce qui lui permettra de le « tuer » si l’utilisateur souhaite stopper l’écoute. J’ai donc commencer par développer ce sous-programme.
Toujours en python : pour la lecture de sons je vais utiliser la bibliothèque « playsound », pour l’installer, c’est simple :
sudo pip3 install playsound
Il faut aussi installer celles qui permet à Linux de lire du streaming:
sudo apt-get install libgstreamer1.0 libgstreamer1.0-dev gstreamer1.0-tools
Mon script recevra 1 seul argument : le fichier audio à lire ou l’url à ouvrir ou une liste de fichiers audio à lire (fichier m3u)
Il s’utilise ainsi :
- Pour lire un fichier mp3 : python3 play.py /home/pi/mon_titre.mp3
- Pour lire une liste de fichiers mp3 : python3 play.py /home/pi/ma_liste.m3u
- Pour écouter Radio Nostalgie : python3 play.py https://scdn.nrjaudio.fm/adwz2/fr/30601/mp3_128.mp3?origine=radio.net
- Télécharger play.mp3 :
A noter : pour que la lecture d’un fichier m3u fonctionne il doit :
- Etre dans le même dossier que les fichiers audio
- Contenir une ligne par fichier audio et ne pas préciser contenir le chemin du dossier
Exemple (ici mon 1er fichier se nomme réellement « 01. Child Fire.mp3 » : avec le 01. devant et les espaces) :
01. Child Fire.mp3 02. Magical Harmony.mp3 03. Not Heal Yet.mp3 04. Chosen One.mp3 05. Blood Brothers.mp3 06. Ignorance.mp3 07. Delicately.mp3 08. Not a Detail.mp3 09. Grey Circles.mp3 10. Ascension.mp3 11. Near Death Experience.mp3
Vous avez essayer playsound.py ? il fonctionne ? Alors passez à la suite. Sinon, recherchez pourquoi. Il s’agit probablement d’un problème de sélection de la carte son par défaut ou d’un oubli d’installer la bibliothèque playsound.
A noter : entre le moment où play.py est lancé et le moment où vous entendez les 1ers sons, il peut se passer quelques secondes voir une bonne dizaine de secondes.
Stockage des données du programme :
Si vous débranchez le réveil puis que vous le réallumez, il va bien falloir qu’il retrouve si l’alarme était activée, à quelle heure, ce qui doit être joué au réveil (lecture de radio, de fichier son). Donc ces données doivent être stockées sur la SD Card.
Pour ces données, j’ai choisi d’utiliser un fichier « param.ini » et si ce fichier n’est pas présent, ce n’est pas grave : le programme va le recréer avec un réveil inactif prévu à 00:00, avec comme sélection : aucune station de radio et aucun fichier mp3 ni liste de fichiers mp3.
De même, je ne compte pas permettre d’utiliser les boutons pour saisir l’url d’une nouvelle station de radio ou le nom d’un nouveau fichier mp3 ! Donc l’utilisateur va devoir choisir parmi une liste d’options possibles. L’utilisateur choisira par clic cours sur un bouton. Chaque clic sélectionnant le fichier suivant. Une fois arrivé au dernier, le prochain clic indiquera qu’aucun fichier n’est sélectionné et au clic suivant que le 1er fichier de la liste l’est. Tandis que l’appui long déclenchera ou arrêtera la lecture du fichier son (ou de la radio)
Ces informations sont stockées dans 2 fichiers json distincts :
Le fichier radiolist.json
Il contient une liste de station radio accessible par internet, voici un exemple :
[ {"id":"0", "name":"MBS" , "url":"https://mbs.ice.infomaniak.ch/mbs-128.mp3"}, {"id":"1", "name":"Nostalgie" , "url":"https://scdn.nrjaudio.fm/adwz2/fr/30601/mp3_128.mp3?origine=radio.net"}, {"id":"2", "name":"Oui FM" , "url":"https://ouifm.ice.infomaniak.ch/ouifm-high.mp3"}, {"id":"3", "name":"Floyd Rock" , "url":"http://91.121.59.45:8013/stream"} ]
L’ensemble est entouré de crochets car c’est une liste de plusieurs stations de radio
Chaque station commence et se termine par une accolade puis une virgule (sauf pour la dernière)
Pour chaque station on retrouve :
- Un id : numéro séquentiel
- name : le nom tel qu’il sera affiché sur l’écran
- url : l’url qui permet de capter la diffusion de la station
Le fichier audiolist.json
Il contient une liste fichiers audio de musique présent sur votre carte SD !
Exemple :
[ {"id":"0", "name":"Amartia list" , "filename":"/home/pi/lcd/musique/amartia_in_a_quiet_place/amartia_in_a_quiet_place.m3u"}, {"id":"1", "name":"Not a detail" , "filename":"/home/pi/lcd/musique/amartia_in_a_quiet_place/08. Not a Detail.mp3"}, {"id":"2", "name":"NDE" , "filename":"/home/pi/lcd/musique/amartia_in_a_quiet_place/11. Near Death Experience.mp3"}, {"id":"3", "name":"Ascension" , "filename":"/home/pi/lcd/musique/amartia_in_a_quiet_place/10. Ascension.mp3"} ]
La structure générale est la même (ce sont des fichiers json) mais cette fois-ci pas d’url mais un « filename » qui est le chemin complet d’accès au fichier. A noter : vous pouvez mettre des fichiers mp3, ogg, wav, flac, mu3 : tout ce qui est fichier son que votre raspberry sait lire.
Voici un script qui permet facilement de créer un fichier m3u
#!/bin/bash # # bash script to create playlist files in music subdirectories # # Steve Carlson (stevengcarlson@gmail.com) find . -type d | while read subdir do rm -f "$subdir"/*.m3u for filename in "$subdir"/* do if [ ${filename: -4} == ".mp3" ] || [ ${filename: -5} == ".flac" ] || [ ${filename: -5} == ".loss" ] || [ ${filename: -5} == ".aiff" ] || [ ${filename: -4} == ".aif" ] then echo "ajout de ""${filename##*/}" echo "a ""$subdir"/"${subdir##*/}.m3u" echo "${filename##*/}" >> ./"$subdir"/"${subdir##*/}.m3u" fi done done
Le fichier alarmelist.json
Il contient une liste fichiers audio utilisables comme réveil matin. Ils doivent être présent sur votre carte SD !
Exemple :
[ {"id":"0", "name":"Beep" , "filename":"/home/pi/lcd/alarme/beep.mp3"}, {"id":"1", "name":"Incendie" , "filename":"/home/pi/lcd/alarme/incendie.mp3"}, {"id":"2", "name":"Coq" , "filename":"/home/pi/lcd/alarme/coq.mp3"} ]
La structure générale est la même que pour les titres à écouter (audiolist.json)
Le mode d’emploi :
Il en faut 1 ! Donc au démarrage, le réveil va afficher une image puis Waveshare 00:00 et enfin l’heure.
Il y a 3 icônes, l’une sera rouge si l’alarme est activée.
Sur le 1er écran, qui affiche l’heure vous pouvez à l’aide des boutons KEY1, KEY2, KEY3 :
- Sélectionner par un appuie court l’élément audio que vous souhaiteriez écouter maintenant (KEY1 pour les beeps, KEY2 pour la radio, KEY3 pour des mp3 ou m3u)
- Par un appuie long sur ces mêmes touches, cela lancera l’écoute / l’arrêt de la source audio correspondante (KEY1 pour les beeps, KEY2 pour la radio, KEY3 pour des mp3 ou m3u)
- Si l’alarme, sonne, vous pouvez l’arrêter par un appuie court sur le mini joystick situé à gauche
- Un appuie long sur le joystick vers le haut vous fait entrer dans l’écran de réglage de l’alarme
Sur le 2ième écran, qui affiche l’heure de l’alarme ainsi que les 3 icônes, vous pouvez :
- Revenir à l’écran affichant l’heure par une pression longue sur le joystick vers le haut
- Par défaut, un curseur est sous la zone dizaine d’heures, vous pouvez le déplacer par un appuie cours par pression sur le joystick
- Le chiffre sous le curseur est modifiable par un appuie cours sur le joystick vers la droite et la gauche
- Les boutons KEY1, KEY2 et KEY3 permettent par appuie court de sélectionner quelle source audio le réveil doit déclencher
- Ils servent aussi, par appuie long à mettre le réveil sur l’une des sources (ainsi qu’à désactiver l’alarme)
Notes
- Pour que l’alarme soit activable, il faut qu’une source sonore soit sélectionnée
- Lorsque vous demandez une lecture audio, elle peut mettre 5,6 secondes à être audible : le Pi charge du cache avant de pouvoir débuter la lecture mais l’arrêt, lui, est instantané.
- Après pas mal de difficultés à distinguer les appuis cours des appuis longs, j’ai été obligé de ne traiter l’action que lorsque le bouton est relâché. Donc tant qu’un bouton est appuyé, rien ne se passera.
- J’ai utilisé un timer de bouton : un appuie court est un appuie de plus de 0,15 seconde et de moins de 0.5 seconde. Un appuie long est un appuie de plus de 0.5 seconde. Si ces réglages ne vous conviennent pas, vous pouvez les changer, is sont dans le fichier param.ini (exprimés en milisecondes)
- L’alarme s’arrêtera soit par un appuie court en pressant le joystick, soit au bout de 4 minutes. Si vous souhaitez modifier cette durée, c’est aussi dans le fichier param.ini.
- La lecture audio (en dehors de l’alarme ne s’arretera pas toute seule : il n’y a pas de fonction « sleep », si vous voulez en mettre une, allez-y.
- Le code est évidement améliorable, c’est vrai que ça s’est finit « à l’arrâche » un peu « énervé » par la gestion des boutons.
- Une fois testé en lançant manuellement pireveil.py, vous pouvez le rentre démarrable automatiquement g^races aux fichiers pireveil.service en lançant installservice.sh
Téléchargement du package du PiReveil (pireveil.py)
Voici donc le zip à télécharger, je laisse les fichiers audios du beeper (ils sont libres de droits, issus de téléchargements gratuits), les url de streaming radio (ils sont libres d’accès et diffusés sur internet) , le fichier m3u et le fichier audiolist (pour exemple) mais le dossier musique vers lesquels ils pointent est vide (les morceaux que j’utilise sont issus d’un album à moi)
En image :
Sur l’image ci-dessous, le Pi Réveil affiche :
- L’heure : il est 11h44
- La date : nous sommes le Lundi 11 Décembre 2023
- Le type de réveil : il est actif (icône rouge) et déclenchera l’écoute de la station de radio MBS à 00h08
- Si on souhaite écouter de l’audio, est actuellement sélectionné : la liste de fichier mp3 (m3u) du groupe Amartia
Démarrage automatique du réveil au boot :
Pour cela, le zip comporte 2 fichiers :
- pireveil.service est la description du service qui lancera le script python pireveil.py
- installservice.sh à lancer (sudo bash installservice.sh) va l’installer et l’activer au démarrage
Remarque sur les 1ers usages :
Si vous ne fabriquez pas de couvercle en impression 3D vous rencontrerez un soucis : le retro éclairage de l’écran OLED est fort et passe dans le petit espace entre l’écran et le circuit imprimé, ce qui éclairera un peu votre chambre. Si vous être sensible à la lumière, cela peut-être gênant. Pour cela, j’ai réalisé quelques modifications :
- Petits bouts de chatterton noir pour fermer ces espaces.
- Le fond d’écran au départ bleu est revenu noir et paramétrable dans le fichier param.ini (section color, valeur de background)
- Le bord d’écran au départ bleu et de 5 pixels est devenu bleu très foncé en 1 pixel
- La couleur du textequi était blanc est devenue paramétrable (section color, valeur de font_1_d et font_1_n pour le texte le plus gros et font_2 pour le texte plus petits.
- La couleur des icônes (hors alarme activée) qui était blanc est devenue paramétrable (section color, valeur de ico_d et ico_n).
- Dans la section couleur, _d correspond à « Diurne » et _n à « Nocturne » : le Pi-Reveil passe de l’un à l’autre automatiquement pour être moins lumineux la nuit. La règle est simple : entre 6h00 et 22h00, la couleur utilisée est celle de jour (_d) sinon, c’est celle de nuit (_n).
- Les couleurs sont au format RGB en hexa, débutant par le caractère #. Pour choisir une nouvelle couleur, allez par exemple sur le site des couleurs HTML : https://htmlcolorcodes.com/fr/
- L’alimentation de la pin 24 de l’écran (retro éclairage), d’abord en direct (pin LCD_BL_PIN dans fichier LCD_1in44.py) est passé en PWM mais le PWM provoquant rapidement des micro-flash , je l’ai mis à 100% (c’est comme s’il n’y avait pas de PWM).
- Pour utiliser confortablement le PWM, achetez l’écran dont le PIN du Brightness (BL) est sur le numéro 18. Ce Pin du Raspberry peut faire du PWM hardware ce qui évite les phénomènes de flash
Toutes ces modifications ont bien amélioré la situation. La meilleur solution serait de réaliser en impression 3D et en noir, un petit boitier qui entoure bien la partie écran du HAT.
Exemple de fichier param.ini
[alarme] heure = 08:15 active = 1 fileindex = radioindex = 1 beepindex = duree = 10 [audi] beepindex = radioindex = fileindex = 0 [click] short = 100 long = 500 [color] font_1_d = #A4A4A4 font_1_n = #535353 font_2_d = #E4E4E4 font_2_n = #939393 ico_d = #D4D4D4 ico_n = #737373 background = #000000
bonjour,
excellent article. j’ai quelques questions d’un novice, pouvez-vous m’indiquer votre adresse e-mail pour ne pas polluer cette page ? cordialement,
Bonjour,
Oui : ch.derenne@gmail.com