Avec Debian 11
Principe de fonctionnement
Un partage sur le réseau héberge un diaporama LibreOffice Impress, quand ce dernier est modifié il est automatiquement téléchargé par un programme en Python et affiché sur la télévision qui est connectée en HDMI à un PC sous la distribution GNU Linux Debian 11. Les dernières versions de mes programmes intègrent également la possibilité de télécharger et de lire en boucle une vidéo. Les paramétrages son enregistrés dans un fichier ini « diaporamaini ». Les fichiers en Python doivent se trouver dans le même dossier.
Le partage Réseau
Le partage Samba sur le réseau à été créé. Les paramètres sont le nom du partage, l’utilisateur y ayant accès avec son mot de passe.
Adressage IP du PC sous Debian
Le PC sous Debian qui héberge les scripts en Python doit se trouver sur le même réseau IP que le partage hébergeant le diaporama.
Environnement pour la programmation et les tests
Pour travailler sur les programmes j’utilise un PC sous Windows que héberge le partage, une machine virtuelle Debian 11 sous VirtualBox permet de programmer et de tester les résultats. La machine virtuelle est sur le même réseau IP que la machine hôte grâce à un pont sur la carte réseau. J’utilise l’éditeur Sublime Text. Un dossier est accessible par les deux machines pour pouvoir récupérer les fichiers créés, l’explorateur de fichier de Debian doit être lancé en administrateur root su avec la commande nautilus.
Installation de Sublime Text sous Debian :
https://wiki.debian.org/SublimeText
Connexion à la machine sous Debian
J’utilise un petit clavier Bluetooth.
Mini Clavier Rii i8 disponible chez Kubii
Programme permettant de paramétrer l’application et de télécharger et lire en boucle les vidéos
Pour lancer le programme depuis le dossier où il se trouve :
./Gestion-Affichage-Dynamique.py
Le programme avec les paramètres de mon environnement de tests.
Les paramètres, nom du serveur ou IP, partage réseau, utilisateur, mot de passe, nom de domaine, fichier de diaporama doivent être saisis puis enregistrés dans le fichier ini.
- [Lancer le Diaporama] Permet de lancer le diaporama en utilisant le paramètres du fichier ini.
- [Enregistrer le fichier ini] Permet d’enregistrer les paramètres saisis dans les champs dans le fichier .ini « diaporamaini ».
- [Lister les fichiers du partage depuis ini] Permet de lister les fichiers contenus dans le partage réseau à partir des paramètres du fichier ini « diaporamaini ».
- [Transférer et lancer la vidéo] Permet de télécharger depuis le partage et de lire en boucle un fichier vidéo sélectionné dans la liste. Le nom du fichier est modifié automatiquement si nécessaire, les espaces remplacés par des _ et les accents supprimés.
Pour arrêter l’exécution du programme en Python depuis le terminal [Ctrl] + [C].
Depuis le menu Fichier ==> Quitter
Programme qui gère le diaporama
Le programme qui gère le diaporama n’a pas d’interface graphique, il lit les données du fichier ini puis télécharge le diaporama et lance LibreOffice Impress pour l’afficher. Quand le diaporama est modifié dans le partage du réseau LibreOffice est arrêté, le nouveau fichier est téléchargé automatiquement, Impress est ensuite relancé avec le fichier mis à jour.
Le mieux est de lancer le programme en lignes de commande depuis un terminal avec votre utilisateur.
Pour lancer le programme depuis le dossier où il se trouve :
./Diapo-py.py
Pour arrêter l’affichage du diaporama [Alt] + [F4].
Pour arrêter l’exécution du programme en Python depuis le terminal [Ctrl] + [C].
Prérequis pour l’installation sur la machine sous Debian 11
Version de Python installée
Pour savoir quelle est la version de Python installée :
python3 --version
Pour l’interface graphique avec Tkinter
Le paquet python3-tk doit être présent sinon on l’installe.
En administrateur root, su + mot de passe :
apt-get install python3-tk
Accès au partage Samba
Vous devez disposer d’un partage réseau Windows ou sous Linux (Samba) avec les login/mot de passe pour y avoir accès. Pour pouvoir accéder au partage réseau vous devez installer le paquet smbclient (client samba) sous Linux en administrateur :
apt-get install smbclient
En cas de problème, il peut être utile de vérifier la connexion au partage depuis le terminal :
smbclient -U utilisateur //ip_du_serveur/nom_du_partage
Pour installer une bibliothèque externe pour Python 3
Installation des paquets nécessaire à la mise en place des bibliothèques pour Python 3. Pip est un gestionnaire de paquets :
apt-get install python3-pip
Installer la bibliothèque pysmbclient (client samba) pour l’accès au partage réseau depuis Python :
pip3 install pysmbclient
Plus d’informations :
https://pypi.org/project/PySmbClient/
Installer la bibliothèque unidecode pour supprimer les caractères accentués des noms de fichiers vidéo :
pip3 install unidecode
Pour la lecture des vidéos sous Debian mplayer doit être installé :
apt-get install mplayer
La commande utilisée pour lire un fichier vidéo en boucle et en plein écran est :
mplayer Fichier_video -loop 0 -fs
Si on adapte le programme à un Raspberry Pi sous Pi OS on utilisera OMXPlayer.
omxplayer --loop fichier_video
Les droits sur les fichiers
Les deux programmes doivent être exécutables et je réduis les droits à l’utilisateur :
chmod 700 nom_du_fichier
Pour le fichier diaporamaini, droits en lecture et en écriture au seul utilisateur :
chmod 600 diaporamaini
Pour une installation sous Debian, j’ai également installé le paquet libreoffice-java-common :
apt-get install libreoffice-java-common
Pour exécuter un programme
./nom_du_fichier.py
Pour supprimer un fichier vidéo téléchargé précédemment :
rm nom_du_fichier
Installation de Java JRE
J’ai également installé Java JRE, attention le nom du fichier téléchargé peut être différent !
Pour télécharger Java JRE pour Linux :
https://www.java.com/fr/download/linux_manual.jsp
J’ai sélectionné Linux x64.
En administrateur root dans un terminal :
cd /usr
mkdir java
cd java
Lancez le navigateur nautilus depuis le terminal en administrateur root su pour copier l’archive TAR téléchargée dans /usr/java
Décompressez l’archive TAR (jre-8u321-linux-x64.tar.gz dans mon cas) pour installer Java :
tar zxvf jre-8u371-linux-x64.tar.gz
Plus d’informations, installation de Java JRE sous Debian 11 (sur mon autre site WEB) :
Si cela ne fonctionne pas sous Debian
Avec Samba sous Debian 11
Pour tester la connexion au partage Samba depuis le terminal sous Linux :
smbclient -U utilisateur //ip_du_serveur/nom_du_partage
Si vous avez le message suivant :
protocol negotiation failed: NT_STATUS_CONNECTION_DISCONNECTED
Solution
Depuis la version 4.11 Samba ne prend plus en charge le vieux protocole SMBv1, seuls SMB2 et SMB3 sont gérés. Certains partages ne sont plus accessibles. Pour voir la version du client Samba :
smbclient --version
Version 4.13.13-Debian Dans mon cas.
Dans le fichier /etc/samba/smb.conf sous la section [global] j’ai ajouté :
client min protocol = NT1
Pour désactiver la boîte de dialogue « Astuce du jour » dans LibreOffice
Outils > Options > LibreOffice > Général > décocher Afficher la boîte de dialogue « Astuces du jour » au démarrage.
Codes sources des programmes en Python
Programme Diapo-py.py
#!/usr/bin/env python3.9
# -- coding: utf-8 --
import pickle
import os
import smbclient
import subprocess
import time
# Version juin 2023
# Lecture du fichier ini
fichierini = "diaporamaini"
pid = ''
# Ouverture du fichier s'il existe et récupération de la liste
if os.path.isfile(fichierini):
fichierSauvegarde = open(fichierini,"rb")
variables = pickle.load(fichierSauvegarde)
fichierSauvegarde.close()
# Affichage d'informations
print("***** Programme de Dominique Renaudeau en langage Python *****")
print("Initialisation des variables")
# Récupération des données dans les variables
serveursmb = variables[0]
partagesmb = variables[1]
utilisateur = variables[2]
mot_de_passe = variables[3]
domaine = variables[4]
fichier_diaporama = variables[5]
else:
# Le fichier n'existe pas
print("Fichier " + fichierini + " non trouvé")
# initialisation des variables
Version_Old = "vide"
local_path = "./" + fichier_diaporama
smb = smbclient.SambaClient(server=serveursmb, share=partagesmb, username=utilisateur,password=mot_de_passe, domain=domaine)
Boucle = True
while Boucle == True:
try:
# Afficher des informations sur le fichier
Version_New = smb.info(fichier_diaporama)
except:
Version_New = Version_Old
if Version_New != Version_Old:
try:
### On arrête l'application LibreOffice ###
pid = os.popen("pidof soffice.bin").read()
if pid != '':
print("Arrêt de l'application LibreOffice")
try:
subprocess.Popen(['/bin/sh', '-c', "pkill office"])
except:
print("LibreOffice n'est pas lancé")
time.sleep(2)
print("LibreOffice n'est pas lancé")
### On supprime l'ancien fichier diaporama s'il existe ###
if os.path.isfile(local_path):
os.remove(local_path)
### Téléchargement du nouveau fichier ###
print("Téléchargement du nouveau fichier et lancement de LibreOffice")
smb.download(fichier_diaporama, local_path)
time.sleep(2)
### Affichage du diaporama ###
Affichage = subprocess.Popen(["libreoffice", "--norestore", "--show", fichier_diaporama], shell=False)
Version_Old = Version_New
time.sleep(60)
pid = os.popen("pidof soffice.bin").read()
print("PID LibreOffice = " + pid)
except:
print("Erreur lors du téléchargement et de l'affichage du diaporama")
else:
time.sleep(20) # Pas de mise à jour - On attend 20 secondes avant de revérifier
if pid == '':
print("LibreOffice n'est pas lancé, vérifiez les paramètres du fichier ini et l'accès au partage réseau.")
exit()
Programme Gestion-Affichage-Dynamique.py
#!/usr/bin/env python3.9
# -- coding: utf-8 --
from tkinter import *
from tkinter import messagebox
import pickle
import os.path
import smbclient
import subprocess
import unidecode # Doit être importée
# Lancer le diaporama avec le second programme en Python
def Lancer_Diaporama():
try:
exec(open("./Diapo-py.py").read())
except:
print("Impossible de lancer le diaporama.")
# Enregistrer la configuration dans le fichier diaporamaini
def Enregistrer():
global serveursmb
global partagesmb
global utilisateur
global mot_de_passe
global domaine
global fichier_diaporama
serveursmb = Serveur_Entry.get()
partagesmb = Partage_Entry.get()
utilisateur = Utilisateur_Entry.get()
mot_de_passe = Mot_de_passe_Entry.get()
domaine = Domaine_Entry.get()
fichier_diaporama = Fichier_du_diaporama_Entry.get()
# Enregistrer mes variables sous forme d'une liste dans un fichier
if serveursmb != "vide" and partagesmb != "vide" and utilisateur != "vide" and mot_de_passe != "vide" and domaine != "vide" and fichier_diaporama != "vide":
variables = [serveursmb, partagesmb, utilisateur, mot_de_passe, domaine, fichier_diaporama]
fichierSauvegarde = open("diaporamaini","wb")
pickle.dump(variables, fichierSauvegarde)
fichierSauvegarde.close()
Mon_bouton_Lister_Fichiers['state'] = NORMAL
Mon_bouton_Lancer_Diaporama['state'] = NORMAL
menufichier.entryconfigure(0,state=NORMAL)
menudiaporama.entryconfigure(0,state=NORMAL)
# Lister les fichiers présents dans le partage réseau en utilisant les paramètres enregistrés dans le fichier diaporamaini
def Lister():
Lire_Ini()
global smb
# Vider la liste de fichiers si elle n'est pas vide
if Liste_Fichiers.size() != 0:
Liste_Fichiers.delete(0,END)
print("Lister les fichiers du partage Samba")
smb = smbclient.SambaClient(server=serveursmb, share=partagesmb, username=utilisateur, password=mot_de_passe, domain=domaine)
dirs = smb.listdir("/")
i = 0
while i < len(dirs):
print (dirs[i])
Liste_Fichiers.insert(i+1, dirs[i])
i += 1
Mon_bouton_Video['state'] = NORMAL
menuvideo.entryconfigure(0,state=NORMAL)
# Lire les informations contenues dans le fichier diaporamaini
def Lire_Ini():
global serveursmb
global partagesmb
global utilisateur
global mot_de_passe
global domaine
global fichier_diaporama
# Lecture du fichier ini
fichierini = "diaporamaini"
# Ouverture du fichier s'il existe et récupération de la liste
if os.path.isfile(fichierini):
fichierSauvegarde = open(fichierini,"rb")
variables = pickle.load(fichierSauvegarde)
fichierSauvegarde.close()
# Affichage d'informations
print("Initialisation des variables depuis le fichier ini")
# Récupération des données dans les variables
serveursmb = variables[0]
partagesmb = variables[1]
utilisateur = variables[2]
mot_de_passe = variables[3]
domaine = variables[4]
fichier_diaporama = variables[5]
else:
# Le fichier n'existe pas
print("Fichier " + fichierini + " non trouvé")
serveursmb = partagesmb = utilisateur = mot_de_passe = domaine = fichier_diaporama = "vide"
# Transférer et Lire le fichier vidéo
def Video():
Fichier_video = "vide"
i=Liste_Fichiers.curselection() ## Récupération de l'index de l'élément sélectionné
try:
Fichier_video = Liste_Fichiers.get(i)
except:
print("Sélectionnez un fichier vidéo")
messagebox.showinfo("Attention !", "Sélectionnez un fichier vidéo .mp4 .avi .MOV.")
# Extention du fichier dans la variable ext
_, ext = os.path.splitext(Fichier_video)
Extentions_Liste = ['.mp4', '.avi', '.MOV']
#if Fichier_video != "vide" and ext == ".mp4" or ext == ".avi":
if Fichier_video != "vide" and ext in Extentions_Liste:
print("Fichier vidéo : "+Fichier_video)
print("Extention du fichier : "+ext)
local_path = "./" + Fichier_video
smb.download(Fichier_video, local_path)
print("Fichier vidéo téléchargé")
# ajout domnique
nom_de_fichier_avant = Fichier_video
print ("Nom de fichier avant : " + nom_de_fichier_avant)
nom_de_fichier_apres = nom_de_fichier(nom_de_fichier_avant)
print("Nom de fichier après : " + nom_de_fichier_apres)
if nom_de_fichier_avant != nom_de_fichier_apres:
print("Le nom de fichier a été modifié")
print("Le fichier doit être renommé")
os.rename(nom_de_fichier_avant, nom_de_fichier_apres)
Fichier_video = nom_de_fichier_apres
else:
print("Le nom de fichier n'a pas été modifié")
print(Fichier_video)
# ajout dominique
subprocess.Popen(['/bin/sh', '-c', "mplayer " + Fichier_video + " -loop 0 -fs"])
else:
print("Sélectionnez un fichier vidéo")
def Aide():
messagebox.showinfo("À propos", "Programme Dominique Renaudeau - Collège Celles et Melle 2023.")
def nom_de_fichier(nom):
# Supprimer les espaces et les caractères accentués du nom du fichier
# Remplacement des espaces
nom = nom.replace(" ","_")
# suppression les caractères accentués
nom = unidecode.unidecode(nom)
return nom
os.chdir(os.path.dirname(__file__)) # Changer le répertoire courant par celui du programme
Lire_Ini() # lire le fichier ini
Fenetre = Tk() # Création de la fenêtre, avec un nom de mon choix Fenetre
# Création des menus
menubar = Menu(Fenetre)
menufichier = Menu(menubar,tearoff=0)
menubar.add_cascade(label="Fichier", menu=menufichier)
menufichier.add_command(label="Lister",state = DISABLED,command=Lister)
menufichier.add_command(label="Enregistrer", command=Enregistrer)
menufichier.add_separator()
menufichier.add_command(label="Quitter", command=Fenetre.destroy)
menudiaporama = Menu(menubar,tearoff=0)
menubar.add_cascade(label="Diaporama", menu=menudiaporama)
menudiaporama.add_command(label="Lancer",state = DISABLED,command=Lancer_Diaporama)
menuvideo = Menu(menubar,tearoff=0)
menubar.add_cascade(label="Vidéo", menu=menuvideo)
menuvideo.add_command(label="Transférer et lancer la vidéo",state = DISABLED,command=Video)
menuaide = Menu(menubar,tearoff=0)
menubar.add_cascade(label="Aide", menu=menuaide)
menuaide.add_command(label="À propos",command=Aide)
Fenetre.config(menu=menubar)
# Paramètres de la fenêtre
Fenetre.title('Paramètres Diaporama et vidéo - Programme : D Renaudeau') #Titre de la fenêtre
Fenetre.geometry("500x400") # On définit la taille de la fenêtre
Fenetre.resizable(width=False,height=False) #Empêcher de redimentionner la fenêtre
# Création d'un interface graphique avec grid
Serveur_Label= Label(Fenetre, text = 'Votre serveur - Nom ou IP :') #Un label pour afficher du texte
Serveur_Label.grid(row=0)
Serveur_Entry= Entry(Fenetre) # On définit l'objet Entry (zone de saisie) qui porte le nom Serveur_Entry
Serveur_Entry.insert(0, serveursmb)
Serveur_Entry.grid(row=0,column=1,ipadx=30) # ipadx=30 pour créer 10 pixels de plus horizontalement
Partage_Label= Label(Fenetre, text = 'Votre partage réseau :')
Partage_Label.grid(row=1,column=0)
Partage_Entry= Entry(Fenetre)
Partage_Entry.insert(0, partagesmb)
Partage_Entry.grid(row=1,column=1,ipadx=30)
Utilisateur_Label= Label(Fenetre, text = 'Votre utilisateur :')
Utilisateur_Label.grid(row=2,column=0)
Utilisateur_Entry= Entry(Fenetre)
Utilisateur_Entry.insert(0, utilisateur)
Utilisateur_Entry.grid(row=2,column=1,ipadx=30)
Mot_de_passe_Label= Label(Fenetre, text = 'Votre mot de passe :')
Mot_de_passe_Label.grid(row=3,column=0)
Mot_de_passe_Entry= Entry(Fenetre,show="*") # Saisie masquée du mot de passe
Mot_de_passe_Entry.insert(0, mot_de_passe)
Mot_de_passe_Entry.grid(row=3,column=1,ipadx=30)
Domaine_Label= Label(Fenetre, text = 'Votre nom de domaine:')
Domaine_Label.grid(row=4,column=0)
Domaine_Entry= Entry(Fenetre)
Domaine_Entry.insert(0, domaine)
Domaine_Entry.grid(row=4,column=1,ipadx=30)
Fichier_du_diaporama_Label= Label(Fenetre, text = 'Votre fichier de diaporama :')
Fichier_du_diaporama_Label.grid(row=5,column=0)
Fichier_du_diaporama_Entry= Entry(Fenetre)
Fichier_du_diaporama_Entry.insert(0, fichier_diaporama)
Fichier_du_diaporama_Entry.grid(row=5,column=1,ipadx=30)
Mon_bouton_Lancer_Diaporama = Button(Fenetre, text = 'Lancer le Diaporama', state = DISABLED, command = Lancer_Diaporama)
Mon_bouton_Lancer_Diaporama.grid(row=6,column=0,ipadx=0)
Mon_bouton_Enregistrer = Button(Fenetre, text = ' Enregistrer le fichier ini', command = Enregistrer)
Mon_bouton_Enregistrer.grid(row=6,column=1,ipadx=0)
Mon_bouton_Video = Button(Fenetre, text = ' Transférer et lancer la vidéo', state = DISABLED, command = Video)
Mon_bouton_Video.grid(row=8,column=0,ipadx=0)
Liste_Fichiers = Listbox(Fenetre)
Liste_Fichiers.grid(row=7,column=1,ipadx=30)
Mon_bouton_Lister_Fichiers = Button(Fenetre, text = ' Lister les fichiers du partage depuis ini', state = DISABLED, command = Lister)
Mon_bouton_Lister_Fichiers.grid(row=8,column=1,ipadx=0)
if serveursmb != "vide":
Mon_bouton_Lister_Fichiers['state'] = NORMAL
Mon_bouton_Lancer_Diaporama['state'] = NORMAL
menufichier.entryconfigure(0,state=NORMAL)
menudiaporama.entryconfigure(0,state=NORMAL)
Fenetre.mainloop() # lance la boucle principale
Téléchargements des fichiers au format ZIP
Dans cette archive zip à télécharger, vous pourrez retrouver les deux fichiers en Python :
Fichiers Python pour l’affichage dynamique
Téléchargements au format PDF
Diapo-py.py
Gestion-Affichage-Dynamique.py