De nos jours, les photographies ne sont plus que numériques ou presque : il est bien sûr possible d’en tirer une sélection au format papier, mais cela est vite chronophage. De plus, je trouve frustrant de devoir choisir un nombre raisonnable de photos à imprimer parmi le nombre très important en ma possession. Pour terminer, je n’ouvre pas non plus tous les jours les albums physiques en ma possession.
Pour remédier à ce problème auquel je ne suis pas le seul à faire face, il existe dans le commerce des cadres photos numériques :
Ces petits écrans sont destinés à être posés sur un meuble et remplacer la bonne vieille photo papier par un défilement de nos meilleurs clichés numériques. On concilie donc la photo matérielle, posée sur le buffet du salon, avec la volatilité de la photo numérique. De quoi rêver de mieux ?
Pourtant, et je parle en connaissance de cause, cela n’est pas la solution idéale :
- Déjà, il faut passer par la case fastidieuse de la sélection des meilleurs clichés, pour les copier sur une carte SD ou une clé USB à insérer au dos de l’appareil. On fait en général ceci une fois ou deux, mais on continue rarement de le faire sur le long terme. Cela se traduit par des photos certes toujours aussi belles, mais rapidement obsolètes.
- Pour être harmonieuses, le ratio largeur/hauteur des photos doit être adapté à celui du cadre. Sinon, sur ces petits écrans, les bandes noires sont particulièrement disgracieuses. Pire encore : les photos portrait affichées sur un cadre paysage ou réciproquement. Il faudrait les recadrer pour qu’elles s’affichent toutes en plein écran : c’est un petit détail qui fait la différence.
- Pour en profiter pleinement, il faut que cet appareil soit allumé à condition et seulement à condition que l’on soit présent dans sa pièce. En effet, d’expérience, s’il est trop souvent allumé sans que personne n’en profite, il finit très rapidement débranché à jamais et ne devient qu’un écran noir qui traîne dans le salon.
- Les appareils que j’ai eu en ma possession permettaient de paramétrer des créneaux horaires d’activité, mais ce n’est pas suffisant. J’ai affiné le mécanisme en rajoutant sur l’un d’eux un capteur d’obscurité car a priori, le cadre ne doit jamais être allumé s’il fait noir (soit je dors, soit je ne suis pas dans la pièce). Malheureusement, il était parfois actif en journée sans que je sois présent, n’ayant pas un emploi du temps réglé comme du papier à musique. Il semble toutefois exister des modèles avec un capteur de mouvement qui permettrait peut-être de résoudre ce problème.
- Le mode aléatoire de choix des photos des équipements que j’ai possédés ne répondait pas à mes attentes : en effet, après un affichage, la photo suivante et tirée aléatoirement parmi les photos disponibles. Cela signifie qu’une photo affichée récemment a autant de chances d’être à nouveau affichée que les autres. Sur le long terme, on a l’impression de souvent voir les mêmes photos. Il faudrait plutôt générer une liste contenant toutes les images dans un ordre aléatoire et ne la regénérer qu’une fois arrivé au bout. Ainsi, on garantit que toutes les images ont été affichées une seule fois.
- Pour terminer, ces écrans dépassent rarement 10″ de diagonale, mais parfois, un écran plus grand serait avantageux.
Bref, vous l’aurez compris, malgré plusieurs essais je n’ai pas trouvé mon bonheur dans le commerce. Du coup, je ne sais pas si le bonheur se fabrique sur un établi, mais un cadre photo, si !
Au boulot !
Partie matérielle
Je pars d’un écran de PC 17″ de marque Belinea récupéré à la déchetterie. Ces écrans ne sont jamais très difficiles à réparer. Je me suis débarrassé de son armature plastique lorsque j’ai réalisé ce cadre quelques années en arrière, et je ne connais plus sa référence. En tout cas, les photos du modèle « 10 17 15 » que l’on trouve sur Internet lui ressemblent beaucoup :
Je ne sais pas quelle technologie est utilisée pour sa dalle LCD, mais les angles de vision sont parfaits et les couleurs vives : c’est l’idéal pour un cadre photo.
Je regrette de ne pas avoir pris de photo du démontage de l’écran. En tout cas, on retrouve sous sa carcasse, derrière la dalle deux circuits imprimés :
- Un premier pour l’alimentation : il est composé d’une alimentation secteur Flyback générant 12V à partir du réseau 230V et d’un autre convertisseur Flyback élevant ces 12V à quelques centaines de Volts pour alimenter les tubes CCFL du rétroéclairage.
- Le second pour le pilotage de la dalle LCD à partir du signal d’entrée VGA.
J’ai prévu d’intégrer cette dalle dans un cadre en bois fait sur mesure, d’une épaisseur limitée. Malheureusement, le transformateur Flyback de l’alimentation secteur est trop épais pour cela : je ne peux donc pas l’intégrer à mon cadre. La partie générant la haute tension pour le rétroéclairage utilise par contre des composants relativement fins que je vais pouvoir conserver. Je sépare donc en deux le PCB de l’alimentation afin de ne garder que cette dernière partie :
À droite, l’alimentation 230V AC/12V DC que je n’utilise plus. Il est inscrit sur la sérigraphie qu’elle est capable de délivrer 1,25A. À gauche, l’élévateur de tension pour alimenter les deux tubes fluorescents du rétroéclairage : c’est la partie que je conserve. J’ai rajouté sur cette dernière une embase circulaire pour l’alimenter directement en 12V, en bas, ainsi qu’un départ pour alimenter le contrôleur de la dalle. En effet, je n’ai pas pu conserver le connecteur d’origine car ce dernier est situé sur la partie du circuit que je retire, à droite. Les fils rouge et noir sont l’alimentation tandis que les deux fils rose servent au pilotage de l’intensité du rétroéclairage via le menu OSD.
Sur la face supérieure de la partie conservée, on voit bien deux blocs distincts et similaires pour générer la haute tension nécessaires aux tubes CCFL. Ils sont composés d’un transformateur et d’un système auto-oscillant constitué de deux transistors et d’une capacité plastique. Une inductance de lissage est présente en amont afin que cet oscillateur très primitif ne pollue pas (trop) le rail d’alimentation 12V. Pour terminer, deux condensateurs haute tension sont connecté en série entre la sortie du transformateur et le tube. Le schéma de principe est le suivant :
Le circuit intégré en boîtier DIP8 que j’ai entouré en partie centrale est un double comparateur KA393A. Je n’ai pas étudié en détail son usage, mais je pense qu’il est utilisé dans le système de variation de luminosité des tubes.
Au verso du circuit imprimé se trouve un certain nombre de composants CMS, dont trois circuits intégrés en boîtier SOIC :
Le circuit central est, sans surprise, un double contrôleur de tube CCFL BI3101A. Il est entouré de deux circuits marqués « 4416 ADA W21B ». Il semblerait que ce soit deux MOSFET SI4416. Cela colle avec le schéma d’application typique du contrôleur CCFL :
En vert, les deux élévateurs auto-oscillants décrits plus haut. L’alimentation de chacun d’eux passe au travers d’un NMOS pour les activer ou non. La variation de luminosité des tubes est obtenue certainement en appliquant un signal PWM sur la grille de ces transistors, à condition que la fréquence de ce PWM soit très inférieure à la fréquence d’oscillation de l’élévateur.
Au verso de la partie 230V/12V que j’ai ôtée, la présence de cet écran à la déchetterie s’explique. C’est tout simplement une piste de cuivre coupée juste après la soudure du connecteur 230V, suite aux différentes connexions et déconnexions successives du cordon d’alimentation :
Bref, passons enfin aux choses sérieuses. Voici donc l’écran une fois débarrassé de sa coque plastique et des différents éléments désormais inutiles. J’ai collé directement les circuits imprimés sur la face arrière de la dalle, après avoir intercalé une feuille de plastique pour l’isolation électrique :
Pour info, avec le PCB d’alimentation entier, cela ressemblait à ceci :
Les deux connecteurs JST en bas à droite de la carte contrôleur (celle avec le vernis vert) sont dédiés à la connexion des haut-parleurs et du petit PCB sur lesquels sont soudés les boutons-poussoirs pour naviguer dans le menu OSD. J’ai déconnecté cette carte de l’écran car elle n’est pas utile au quotidien, mais je la conserve précieusement au cas où j’aie des réglages à faire à l’avenir :
Vue de face :
Pour remplacer l’alimentation secteur que j’ai retirée, j’utilise un bloc secteur délivrant 12V sous 2A. Il était à l’origine conçu pour alimenter une Livebox. En blanc, il est plutôt discret et s’intégrera assez bien dans mon intérieur :
Au niveau informatique, le coeur du système est un Raspberry Pi Zero. Sa sortie vidéo est de type HDMI, non compatible avec mon moniteur qui n’accepte qu’un signal VGA. Plutôt que d’acheter un convertisseur HDMI/VGA actif, je préfère utiliser l’interface VGA666 : elle permet de créer un signal analogique VGA à partir de ses GPIOs.
En fait, il ne s’agit ni plus ni moins que de trois DACs résistifs de 6 bits dont le schéma est le suivant :
La tension sur Vout est égale à la somme des tensions sur chaque GPIO divisées par leur résistance associée :
Cette structure est extrêmement simple mais a toutefois un ÉNORME inconvénient : la tension de sortie du DAC est proportionnelle à la tension à l’état haut des GPIO, qui n’est pas vraiment précise, ni stable. De plus, avec 6 bits par couleurs, on peut en afficher « seulement » 262144, ce qui peut paraître peu par rapport aux 16 millions de couleurs –minimum– générées sur une sortie vidéo classique.
Il est donc assez bizarre à première vue de générer un signal analogique sensible quel qu’un signal vidéo de cette manière, mais en pratique, cela fonctionne plutôt bien !
Le schéma complet est le suivant (cliquez pour l’afficher en taille réelle). Les résistances sont en double car une double empreinte est présente sur le PCB vendu par l’auteur :
Au niveau logiciel, tout est prémâché : il suffit de quelques lignes à ajouter dans le fichier /boot/config.txt
.
J’ai réalisé ce DAC sur du Veroboard avec des résistances à 1% aussi proches que possible des valeurs théoriques. J’ai aussi inclus un DC/DC pour générer le 5V nécessaire au Raspberry Pi à partir de l’alimentation de générale de l’écran en 12V. Ce dernier est basé sur un circuit TL2575HV-5.0 dont il me restait des échantillons commandés pour réaliser l’onduleur de mon vélo électrique. J’intègre pour finir un PMOS pour commuter l’alimentation du cadre à partir d’un GPIO du Raspberry Pi :
Le câble en haut amène le signal vidéo à la carte contrôleur de l’écran. J’ai utilisé un câble blindé pour acheminer les composantes analogiques R, V et B. Les deux fils bleus apportent les signaux de synchronisation horizontale et verticale.
Détail du circuit. J’ai entouré les 3 blocs fonctionnels et je vous laisserai deviner où sont le DAC résistif, le DC/DC et le système de commutation d’alimentation de l’écran :
Le Raspberry Pi Zero qui n’existait pas en version W à l’époque ne dispose d’aucune connectivité réseau. Je lui adjoins donc une clé USB Wi-Fi. Comme il ne dispose que d’un port micro-USB, je dois lui ajouter un port USB type A de taille complète au bout d’un câble :
Je réalise ensuite l’encadrement en bois. Pour cela, j’ai acheté des tasseaux de 8×23 mm de côté et de 2,5m de longueur. Je les colle ensuite de manière à former un L qui va venir entourer la dalle LCD :
Je les ai d’abord collés perpendiculairement sur toute leur longueur afin de former un L de 2,5m de long. C’est seulement après que j’en ai coupé quatre morceaux à la scie à onglet pour former le cadre :
Voici donc le résultat, une fois les cartes électroniques (alimentation de l’écran, carte à Raspberry Pi et contrôleur LCD) pistocollées à l’arrière :
Mise sous tension… et ça boote !
Yapluka écrire le soft maintenant.
Partie logicielle 1 : l’affichage des photos à proprement parler
La réalisation matérielle étant terminée, je dois maintenant écrire le logiciel qui affiche régulièrement des photos à l’écran.
Je n’ai jamais utilisé de gestionnaire de bureau graphique sur un Raspberry Pi : pour les applications embarquées que j’ai réalisées, une console m’a toujours suffi. Ce projet ne va pas bousculer mes habitudes : j’ai certes un écran à piloter, mais il me paraît bien plus simple d’utiliser le framebuffer que le système de fenêtrage X.
Les premiers essais sont faits en utilisant fbi, qui ne répond pas à mes attentes :
Je veux avoir le contrôle total de l’affichage et fbi ne me procure pas assez de souplesse pour cela. Je préfère donc écrire mon propre logiciel, en C. La bibliothèque graphique SDL me semble assez adaptée et de plus, je la connais déjà un peu : c’est grâce à elle que j’ai appris le langage sur feu Le Site du Zéro il y a déjà une quinzaine d’années de cela. Je m’empresse donc de réaliser mon Hello World :
Accessoirement, cela me permet de me rendre compte que je m’étais initialement emmêlé les pinceaux lors du câblage du DAC : certains poids binaires étaient inversés, parfois même avec des couleurs différentes. Cela se traduisait par des aberrations dans ce dégradé. Sur la photo ci-dessus, les erreurs ont été corrigées.
A noter que le Raspberry Pi est en permanence sous tension et que c’est le logiciel qui se charge d’allumer ou d’éteindre l’écran. Il est relativement simple et fonctionne de la manière décrite ci-dessous.
Il est d’abord contrôlé par deux fichiers textes stockées en mémoire volatile (ramdisk) pour limiter les cycles d’écriture sur la carte SD :
- cadre_actif.txt : sa présence met le cadre en fonctionnement, son absence l’éteint.
- update.txt : sa présence regénère la liste aléatoire des photos à afficher. Le répertoire contenant les images est donc listé, cette liste est mélangée pour obtenir un affichage aléatoire puis sauvegardée.
Deux autres fichiers, cette fois stockées sur la carte SD afin qu’ils soient conservés même après une extinction ou un redémarrage du système, gèrent la file d’affichage des photos :
- liste.txt contient les chemins et l’ordre de toutes les images à afficher.
- num_photo.txt contient le numéro dans la liste de la dernière photo affichée et permet de la retrouver au prochain allumage du cadre.
Pour réaliser les transitions entre les images, je souhaitais un fondu par transparence. Autrement dit, l’image suivante doit être affichée par dessus l’actuelle avec des niveaux de transparence successifs décroissants, de 100% à 0%. Cela demande beaucoup de ressources au Raspberry Pi Zero : chaque image intermédiaire nécessite plusieurs secondes pour être générée. Etant donné qu’il faut, d’après mes essais, une centaine d’images intermédiaires pour obtenir une transition fluide, cette dernière est très lente : plusieurs minutes. Je préfèrerais qu’elle ne dure que quelques secondes.
Je remédie à ce problème en mettant à profit le confortable espace de 512 Mo de RAM du mini-ordinateur. Sitôt une image affichée, le programme s’attelle à générer toutes les images intermédiaires du fondu suivant et les conserve en RAM. Une fois toutes générées, elles sont affichées successivement avec 50ms entre chacune d’elles. La RAM est alors vidée et le cycle recommence.
La définition de l’écran (et donc de chaque image) étant de 1280×1024 pixels, chacune occupe 3,75Mo de RAM, puisqu’elles ne sont plus compressées. La transparence étant gérée sur 8 bits, 256 niveaux sont possibles. Calculer une image tous les deux niveaux de transparence donne 128 images à stocker, soit 480Mo : cela laisse trop peu de RAM pour le reste du système. Je me contente donc de calculer une image toutes les 3 valeurs de transparence pour en avoir 85. Les images occupent alors au maximum 318Mo de RAM, ce qui me paraît largement acceptable.
Voici en vidéo le rendu obtenu :
Partie logicielle 2 : l’interface Web
Comme vous avez pu vous en rendre compte si vous avez lu mes autres articles, je fais presque toujours tourner une interface Web en parallèle d’un programme console écrit en C : c’est pour moi un bon moyen d’interagir graphiquement avec lui. Ce projet ne déroge pas à cette règle.
Je voudrais pouvoir visualiser dans une galerie photo les images présentes dans le cadre ainsi que l’allumer et l’éteindre. N’étant pas très bon designer ni développeur Web, je recycle une galerie photo que j’avais faite avec un ami il y a… très longtemps, ce qui explique le style un peu retro :
La galerie affiche les images dans le même ordre que le cadre et met en surbrillance l’image actuellement affichée. Les deux boutons On-Off du haut se contentent de créer ou de supprimer le fichier cadre_actif.txt.
Partie logicielle 3 : la mise à jour automatique et l’intégration avec la domotique
Pour rappel, les critères qui ne me convenaient pas dans les produits du commerce sont les suivants :
- L’écran est trop petit.
- La photo suivante à afficher est choisie aléatoirement parmi la totalité au lieu de la choisir parmi celles qui n’ont pas encore été affichées.
- Ils peuvent être allumés lorsque l’on en a pas besoin, ou à l’inverse ne pas être allumés lorsque l’on est présent.
- La mise à jour de la carte SD ou de la clé USB est fastidieuse… et manuelle.
- La taille des photos n’est pas forcément adaptée à la taille de l’écran ce qui conduit à l’apparition de bandes noires (même si on pourrait bien sûr les recadrer préalablement).
Les deux premiers point ont déjà été résolus : il reste les trois suivants !
La détection de présence
Le plus simple serait certainement un capteur de mouvement PIR connecté à un GPIO du Raspberry Pi. Malheureusement, je ne voulais pas de cet objet disgracieux autour du cadre.
J’ai ensuite brièvement essayé de pinguer régulièrement le smartphone des occupants de l’appartement, après leur avoir donné un bail DHCP permanent dans l’interface de configuration du routeur. Toutefois, je n’ai pas vraiment mené à son terme cette solution : la réponse aux pings, lorsque les téléphones sont en veille, est assez erratique. De plus, j’avais peur que cela empêche leurs modules WiFi d’entrer en sommeil et que cela diminue l’autonomie de leur batterie. De plus, le cadre resterait actif même si tout le monde est dans d’autres pièces.
Finalement, je me suis rendu compte que l’éclairage à LED du plan de travail de la cuisine (ouverte sur mon salon) est vraiment corrélé à notre présence dans la pièce. Je décide donc de m’appuyer dessus pour savoir si le cadre doit être allumé ou éteint.
Cet éclairage utilise un bloc d’alimentation AC/DC 12V. Je tire donc un câble deux conducteurs jusqu’à l’interface du serveur. Là, il alimente un optocoupleur qui vient piloter une entrée de la carte d’interface. Cette dernière envoie alors une trame au serveur lors de l’allumage ou de l’extinction de la cuisine. Pour terminer, le serveur, lors de la réception de cette trame, fait une requête HTTP au serveur Web du cadre photo grâce à cURL.
Note : je décris (entre autres) cette interface matérielle dans l’épisode 4 de la domotique.
Il aurait été plus simple d’apporter le câble de l’éclairage directement au cadre photo plutôt que de passer par tous ces intermédiaires, mais cela me permet de ne pas avoir à le camoufler : l’ordre d’allumage ou d’extinction est reçu via le réseau Wi-Fi.
La mise à jour automatique des photos
Parce que c’est une chose essentielle quand on tient un minimum à ses données, le disque dur SSD de mon PC portable est régulièrement sauvegardé sur le serveur. Puisqu’il possède par ce biais une copie des photos, il est donc capable de maintenir le cadre à jour !
Il lui reste seulement à connaître quelles photos ont été sélectionnées pour être affichées sur le cadre : tous mes clichés, même si je ne conserve que les plus réussis, ne méritent pas d’être exposées. Sur mes cadres photos précédents, je dupliquais ou déplaçais les fichiers choisis dans des répertoires spécifiques. Cela engendrait une certaine lourdeur et je n’ai jamais été vraiment satisfait de cette solution. Pour cette version, j’utilise les méta-données des photos, en particulier la note de 1 à 5 qu’il est possible d’attribuer à chaque image grâce au tag Xmp.Rating. Ainsi, la note de chaque photo est intrinsèquement liée au fichier lui-même.
J’ai donc réalisé un autre programme qui tourne en tâche de fond sur le serveur et scrute régulièrement si une nouvelle sauvegarde a été effectuée. Dans ce cas, il passe en revue toutes les images et lit leur note. La liste des photos suffisamment bien notées est générée et comparée à la précédente. D’éventuelles photos rajoutées sont automatiquement redimensionnées et recadrées pour s’adapter parfaitement au cadre grâce à ImageMagick. J’étais initialement un peu réticent à l’idée de recadrer automatiquement les images : sans savoir ce que contenait les zones retirées, elles risquaient de perdre leur intérêt. Cela est particulièrement significatif sur les photos d’orientation Portrait recadrées en Paysage : la moitié de l’image est perdue. Toutefois, après essai, je trouve le résultat très acceptable pour la majorité des clichés. En tout cas, je préfère largement cela à la présence de bandes noires.
Pour terminer, les nouvelles photos recadrées et redimensionnées sont envoyées sur la carte SD du cadre photo via rsync. Comme leur définition a été abaissée à 1280×1024 pixels, elles n’occupent que peu de mémoire.
J’ai terminé d’écrire ce billet, j’espère qu’il vous a plu. A noter que j’ai créé un logiciel sur PC pour pouvoir facilement et surtout rapidement trier et noter les nombreuses photos, une fois de retour de vacances. Il fera l’objet d’un prochain article très prochainement 😉
[Mise à jour le 22/03/20] : il est maintenant disponible ici !