Tutoriel : Partie 3 - Installation de Django

A faire

  • Créer un environnement virtuel pour y installer Django
  • Installer Django
  • Créer un projet Django et une application
  • Procéder à certains réglages de Django
  • Créer les modèles et les vues de l’application
  • Créer des fichiers css et html (templates)
  • Capturer et stocker des images fixes prises par les caméras
  • Lancer le site

Dossiers et environnement virtuel

  • Pour éviter des problèmes de conflit entre python2 et python3, il est préférable d’installer Django dans un environnement virtuel.
  • De manière à structurer les dossiers nous allons utiliser une arborescence de ce type :
  • C’est dans folder que nous allons créer un environnement virtuel que nous appellerons folder_venv. Django sera installé dans cet environnement virtuel.
  • Puis nous créerons un projet Django dans le dossier folder. Ce projet s’appellera project.
  • Dans ce projet, nous créerons une application que nous appellerons camera.
  • Vous pouvez choisir les noms folder et project que vous souhaitez (mais cela n’est pas souhaitable), à condition de les modifier dans le fichier configuration.ini (section [paths], clés folder et project).
  • Il est très vivement conseillé de ne pas modifier le nom de l’application camera, sinon vous devrez changer le nom de l’application dans différents fichiers html ou python que nous créerons plus tard.

Création d’un environnement virtuel

  • Créer le dossier folder
    mkdir ~/folder
    
  • Créer l’environnement virtuel
    cd ~/folder
    python3 -m venv folder_venv
    

    (Ne pas omettre le 3 de python)

  • Activer l’environnement virtuel
    source ~/folder/folder_venv/bin/activate
    
  • L’invite de commande ne sera plus du type :
    pi@Foo:~$
    

    mais du type

    (folder_venv) pi@Foo:~$
    

N.B. : dorénavant, lorsque les commandes seront tapées dans l’environnement virtuel, elles seront précédées du symbole (venv)

  • Pour désactiver l’environnement virtuel taper la commande deactivate

    (venv) deactivate
    

Installation de Django

  • Se mettre en environnement virtuel :
    source ~/folder/folder_venv/bin/activate
    
  • Installer Django
    (venv) python -m pip install Django
    
  • Django va s’installer dans l’environnement virtuel. Ici le 3 de la commande python n’est plus utile car il n’y a plus d’ambiguïté de choix, seul python3 étant installé dans l’environnement virtuel.
  • Vérifier l’installation et la version
    (venv) python -m django --version
    

qui doit renvoyer une sortie du type : 4.0.2 (en fonction de la version)

Création du projet et de l’application

Créer le projet project

  • Se mettre dans le répertoire folder (en environnement virtuel)
    (venv) cd ~/folder
    
  • Créer le projet
    (venv) django-admin startproject project
    
  • L’arborescence du dossier folder est la suivante :

Créer l’application camera 

  • Se mettre dans le même dossier que celui contenant manage.py,
    (venv) cd ~/folder/project
    
  • Créer l’application
    (venv) python manage.py startapp camera
    
  • Django a créé un nouveau répertoire. L’arborescence est :

Structure de l’application camera

L’application camera va comporter huit vues, c’est à dire huit pages web différentes.

  • accueil : la page d’accueil du site.
  • historique : page présentant des photos prises à intervalle régulier par les trois caméras, sur une durée déterminée (par exemple, toutes les 5 minutes sur les 24 dernières heures)
  • parHeure : page présentant les photos prises sur une durée déterminée (par exemple, toutes les 5 minutes sur les douze dernières heures)
  • nuit : page présentant les photos prises entre le coucher et le lever du soleil (par exemple, toutes les 3 minutes du coucher au lever le lendemain)
  • stream_1 : flux vidéo en direct de la première caméra
  • stream_2: flux vidéo en direct de la deuxième caméra
  • stream_py : flux vidéo en direct de la caméra py
  • stream_AllCam : flux vidéo en direct des trois caméras

Réglage du fichier settings.py

  • Ouvrir le fichier settings.py (vous n’avez pas besoin d’être en environnement virtuel)

    nano ~/folder/project/project/settings.py
    
  • Apporter les modifications suivantes

  • ALLOWED_HOSTS : ajouter l’IP locale de la Raspberry

    ALLOWED_HOSTS = ['<local IP raspberry>']
    
    par exemple `['192.168.1.49']`
    
  • INSTALLED_APPS : ajouter ‘camera.apps.CameraConfig’ dans la liste existante

    INSTALLED_APPS = [
      'camera.apps.CameraConfig', 
      'django.contrib.admin', 
      'django.contrib.auth', 
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles', 
      ]
    
  • DATABASES : ajouter votre time-zone

    DATABASES = {  
      'default': {  
      'ENGINE': 'django.db.backends.sqlite3',  
      'NAME': BASE_DIR / 'db.sqlite3',  
      'TIME_ZONE': 'Europe/Paris'  
      }  
      }  
    

Ceci permet de régler des problèmes de prise en compte des dates par la base de données. Si vous optez pour une base de données autre que sqlite3, vous devrez réécrire les parties des scripts qui font appel au module sqlite3.

  • LANGUAGE_CODE et TIME_ZONE : adapter la langue et la time-zone
    LANGUAGE_CODE ='fr'
    TIME_ZONE = 'Europe/Paris'
    
  • STATICFILES_DIRS : ajouter en fin de fichier (en dessous de la ligne STATIC_URL par exemple)
    STATICFILES_DIRS = [
      BASE_DIR / "static", 
      "/var/www/stock",
      ]
    

si vous avez gardé cette valeur de la clé stockde la section [paths] du fichier de configuration.
C’est dans ce dossier /var/www/stock que seront stockées les photos prises par les caméras.

Créer les modèles de l’application

  • Les modèles vont permettre de définir les tables de la base de données.
  • Nous allons créer deux modèles :
    • un modèle Appareil qui caractérise chaque caméra
    • un modèle Photo qui caractérise les photos qui vont être stockées
  • Ouvrir le fichier ~/folder/project/camera/models.py
    nano ~/folder/project/camera/models.py
    
  • Supprimer son contenu
  • Remplacer son contenu par celui du fichier models.py disponible ici.
  • Prendre en compte les modifications ; on crée la base de données et on effectue les migrations (en environnement virtuel)
    (venv) python ~/folder/project/manage.py makemigrations
    (venv) python ~/folder/project/manage.py migrate
    
  • Créer les trois caméras
    • Ouvrir le shell
      (venv) python ~/folder/project/manage.py shell
      
    • Créer les caméras
      >>> from camera.models import Appareil 
      >>> c = Appareil(name="Cam_1")
      >>> c.save()
      >>> c = Appareil(name="Cam_2")
      >>> c.save()
      >>> c = Appareil(name="Cam_py")
      >>> c.save()
      
    • Vérifier que les trois caméras sont bien crées
      >>> Appareil.objects.all()
      <QuerySet [<Appareil: Cam_1>, <Appareil: Cam_2>, <Appareil: Cam_py>]>
      
    • Quitter le shell : Ctrl+D
  • Nous n’avons pas utilisé l’interface Admin de Django. Celle-ci nous est inutile, toutes les actions sur la base de données se feront directement par des scripts python.

Modifier le fichier urls.py de ~/folder/project/project

  • Ouvrir le fichier
    nano ~/folder/project/project/urls.py
    
  • Modifier la ligne d’import et la ligne urlpatterns de la manière suivante
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
      path('camera/', include('camera.urls')),
      path('admin/', admin.site.urls),
      ]
    
  • Un exemplaire du fichier est disponible ici.

Créer un fichier urls.py dans ~/folder/project/camera

  • Créer et ouvrir le fichier en écriture
    nano ~/folder/project/camera/urls.py
    
  • Coller/copier dans ce fichier le contenu du fichier urls.py (camera) disponible ici.

Modifier le fichier views.py dans ~/folder/project/camera

Modifier le fichier

  • Ouvrir le fichier
      nano ~/folder/project/camera/views.py
    
  • Effacer son contenu et copier/coller le contenu du fichier views.py (V1) disponible ici.

Commentaires sur ce fichier

  • La vue historique (def historique(request)) permet de visualiser les captures de photos des trois caméras sur les N dernières heures en ne sélectionnant qu’une photo sur n, les photos étant prises à une fréquence f. Les paramètres N, n et f sont modifiables dans le fichier de configuration. Il s’agit des clés historique, display_jour et capture de la section [fréquences]. Si la clé historique est à 5, la clé display_jour à 2 et la clé capture à 60 cela signifie que les caméras prennent une photo toutes les 60 secondes et qu’on visualisera sur les 2 derniers jours une photo sur cinq (c’est à dire une photo toutes les 300 secondes).
  • La vue parHeure (def parHeure(request)) permettra de visualiser toutes les photos des trois caméras sur les N dernières heures prises à la fréquence f, sans sélection. N et f ont la même valeur que dans la vue historique. La présentation se fera en pagination.
  • La vue nuit permet de visualiser les captures de photos entre le coucher du soleil et le lever du lendemain. Les photos sont prises à la fréquence f (la même que dans la vue historique) et on peut ne sélectionner qu’une photo sur p, p étant la clé nuit de la section [fréquences] du fichier de configuration.
  • Les fonctions de streaming n’appellent aucun réglage, sauf l’adresse IP locale de la raspberry (clé raspIP de la section [hosts] et les ports de sortie des flux (clés cam_1_port, cam_2_port et cam_py_port de la section [camera])
  • Par défaut : N = 24 heures (clé display_jour=1, soit 24 heures), n = 4, p = 3, f = 60 (en secondes) ; les ports des flux sont par défaut 8081, 8082 et 8084.

Lever et coucher du soleil

  • Les heures de lever et de coucher du soleil sont calculées à l’aide du module suntimes
  • Installer le module suntimes (en environnement virtuel)
    (venv) pip install suntimes
    
  • Si besoin installer jdcal et tzlocal (a priori les dépendances s’installent automatiquement)
    (venv) pip install jdcal
    (venv) pip install tzlocal
    
  • Le constructeur SunTimes du module suntimes prend trois paramètres de localisation : longitude, latitude et altitude qu’il faut modifier dans le fichier de configuration.
  • Ouvrir le fichier de configuration
    sudo nano /etc/camera/configuration.ini
    
  • Dans la section [locate] modifier les valeurs par défaut par celles de votre lieu. Ces valeurs sont disponibles sur geoportail ou sur google earth.

A renseigner impérativement dans le fichier de configuration

  • Dans la section [hosts] chercher la clé raspIP
  • Remplacer la valeur par l’IP locale de votre Raspberry
  • Création des dossiers css et logo
    • Les fichiers css sont situés dans ~/folder/project/camera/static/camera/css/
    • Ce chemin paraît compliqué à première vue, mais il est le chemin recommandé dans les différentes tutoriels relatifs à Django. On suit cette procédure, même si la simplicité du site (une seule application) ne la justifie pas.
    • Création des dossiers
      cd ~/folder/project/camera
      mkdir static static/camera static/camera/css static/camera/logo
      
  • Remarques sur le fichier css :
    • ce fichier a été récupéré à partir d’un site personnel construit antérieurement
    • il y a des redondances et des classes superflues
    • le design du site n’est pas optimal, loin s’en faut
    • pour simplifier, tout le css a été regroupé dans un seul fichier
    • il est possible de le fractionner en plusieurs fichiers, mais dans ce cas il faudra appeler chaque fichier dans le base.html
  • Vous pouvez, bien sûr, modifier à votre convenance le css. Il faudra alors modifier l’appel des fichiers css dans le fichier base.html (chapître suivant).
  • Création de global.css
    • Créer et ouvrir en écriture le fichier global.css
      nano ~/folder/project/camera/static/camera/css/global.css
      
    • Copier/coller dans l’éditeur de texte le contenu du fichier global.cssdisponible ici
  • Logo favicon
    • La favicon est une image qui s’affiche dans la barre d’adresse web en regard de l’URL.
    • Charger sur la Raspberry une image au format png d’environ 40x40 pixels
    • Nommer l’image logo.png
    • Déplacer l’image dans le dossier ~/folder/project/camera/static/camera/logo
    • Pour charger l’image logo.png située dans votre dossier /home/user/Bureau de votre ordinateur (par exemple) vers le dossier de la Raspberry taper dans un terminal la commande suivante :
      scp /home/user/Bureau/logo.png pi@<local IP Raspberry>:/home/pi/folder/project/camera/static/camera/logo
      
    • En modifiant les chemins et l’IP de la Raspberry en fonction de vos paramètres ; à l’invite de commande, entrer le mot de passe de la Raspberry.

Créer les fichiers html (templates)

  • Création du dossier templates
    • Les fichiers html sont situés dans ~/folder/project/camera/templates/camera/
    • Création des répertoires :
      cd ~/folder/project/camera
      mkdir templates templates/camera 
      
  • A propos de base.html
    • base.html est le template (gabarit) de base dont vont hériter les autres templates.
    • C’est dans ce gabarit que sont appelés les fichiers css et la favicon. Si vous avez modifié le chemin des fichiers css, c’est dans base.html que vous devez reporter ces modifications.
    • De même, c’est dans ce gabarit que vous pouvez modifier l’aspect du menu, du header ou du footer (notamment, le nom qui apparaît en bas de page et le logo).
    • Si vous modifiez le nom de ce gabarit ou si votre application ne s’appelle pas camera, vous devrez modifier en conséquence la première ligne {% extends "camera/base.html" %} des autres gabarits.
  • Création de base.html
    • Créer et ouvrir en écriture le fichier base.html
      nano ~/folder/project/camera/templates/camera/base.html
      
    • Copier/coller dans ce fichier le contenu du fichier base.html disponible ici
  • Procéder de même pour les autres fichiers html
    • accueil.html dont le contenu est disponible ici
    • historique.html dont le contenu est disponible ici
    • nuit.html dont le contenu est disponible ici
    • parHeure.html dont le contenu est disponible ici
    • stream_1.html dont le contenu est disponible ici
    • stream_2.html dont le contenu est disponible ici
    • stream_py.html dont le contenu est disponible ici
    • stream_AllCam.html dont le contenu est disponible ici

Capturer les images et les stocker

Créer les répertoires de stockage

  • Créer le répertoire /var/www/stock
    sudo mkdir /var/www/stock
    
  • Créer les sous-répertoires pour les différentes caméras
    cd /var/www/stock
    sudo mkdir Camera_1 Camera_2 Camera_py 
    
  • Changer le propriétaire de /var/www/stock
    sudo chown -R pi /var/www/stock
    

Ecrire le script de capture des photos

  • Ce script sera lancé au démarrage et tournera en boucle en effectuant :
    • la capture des images pour chaque caméra à la fréquence choisie
    • l’inscription dans la base de données des caractéristiques relatives à chaque photo (caméra, date de prise, nom de la photo, répertoire de stockage)
  • Créer le script
    • Créer et ouvrir en écriture le fichier getCamerasAndRegister.py
      nano ~/script/getCamerasAndRegister.py
      
    • Copier/coller dans ce fichier le contenu du fichier getCamerasAndRegister.py disponible ici
  • Lancer le script au démarrage de la Raspberry
    • Ouvrir le cron en édition
      crontab -e
      
    • Ajouter la ligne suivante
      @reboot python3 /home/pi/script/getCamerasAndRegister.py
      

Ecrire le script de destruction périodique des photos

  • Tous les jours on efface les images datant de plus de N jours, N étant la clé delay-delete de la section [frequences] du fichier de configuration.

  • Par défaut, la valeur de N est 2, c’est à dire qu’on ne conserve les images que deux jours.

  • Il est indispensable d’effectuer cette tâche régulièrement afin que la carte micro-SD ne soit pas saturée.

  • Créer et ouvrir en écriture le fichier suppressFiles.py

    nano ~/script/suppressFiles.py
    
  • Copier/coller dans ce fichier le contenu du fichier suppressFiles disponible ici

  • Lancer le script tous les jours à 03H10 du matin (par exemple) dans le crontab

    • Ouvrir le cron en édition
    crontab -e
    
    • Ajouter la ligne suivante
    10 03 * * * python3 /home/pi/script/suppressFiles.py
    

Lancer Django au démarrage

  • Le script lance le serveur de Django au démarrage de la raspberry sur le port 8000 par défaut (paramétrable dans /etc/configuration.ini)
  • Pour accéder au site depuis un appareil du réseau, vous devez avoir indiqué l’adresse IP locale de la raspberry dans ALLOWED_HOSTS du fichier ~/folder/project/project/settings.py (par exemple ALLOWED_HOSTS = [‘192.168.1.49’])
  • Créer et ouvrir en écriture le fichier runDjango.py
    nano ~/script/runDjango.py
    
  • Copier/coller le contenu du fichier runDjango.py disponible ici
  • Lancer le script au démarrage dans le crontab
    • Ouvrir le crontab en édition
      crontab -e
      
    • Ajouter la ligne suivante
      @reboot python3 /home/pi/script/runDjango.py
      
    • Il peut être nécessaire, notamment en fonction du modèle de Raspberry de donner un temps de latence au démarrage (ici 120 secondes)
      @reboot sleep 120 && python3 /home/pi/script/runDjango.py
      

Tester le site

  • Rebouter le système
    sudo reboot
    
  • Attendre que les scripts des différentes caméras soient lancés.
  • Dans la barre d’adresse d’un navigateur taper <local IP Raspberry>:8000/camera/ (par exemple : 192.168.1.49:8000/camera/)
  • Vous devez obtenir ce résultat :
  • Si les caméras sont bien lancées, vous devez voir les flux en cliquant sur le bouton En direct. Bien sûr, pour les autres pages html, au début vous ne verrez que peu ou pas d’images.
  • Au fil du temps, les différents historiques (Histoire, Heure par Heure et Nuit) pourront être longs à s’afficher, le nombre d’images à charger étant élevé. C’est, à l’évidence, une faiblesse des scripts.

Horaire d’été / horaire d’hiver

Position du problème

  • Lors du passage de l’horaire d’été à l’horaire d’hiver la même heure va être doublée
  • Ceci ne pose pas de problème au niveau du stockage des photos : la photo qui portera le même nom écrasera la photo homonyme
  • Par contre au niveau de la base de données, deux lignes vont exister pour une photo prise à la même heure
  • Lorsqu’on voudra afficher les historiques, une erreur 500 sera renvoyée, Django ne sachant pas quelle image afficher

Solution 1

  • Éteindre la raspberry avant le changement d’heure
  • Rallumer la raspberry après le changement d’heure

Solution 2

  • Après le changement d’heure, alors que l’erreur 500 va s’afficher, vider la table de la base de données contenant les informations des photos
  • Se connecter en ssh à la raspberry
  • Une fois connecté, se mettre dans le shell squlite en tapant dans le terminal
pi@raspberry:~ $ sqlite3
  • Ouvrir la base de données (à adapter si les différents noms ont été changés)
sqlite > .open "/home/pi/folder/project/db.sqlite3"
  • Éventuellement vérifier le nom des tables de la base
sqlite > .tables
  • Supprimer les donées de la table camera_photo (si ce nom a été conservé)
sqlite > DELETE FROM camera_photo;
  • Quitter le shell sqlite
sqlite > Crtl+D
  • Vérifier que l’historique ne renvoie pas d’erreur 500
  • Au bout d’une minute de nouveaux enregistements sont inscrits dans la base et on peut les apercevoir dans la vue parHeure

A ce stade - Prochaine étape

A ce stade

  • On dispose d’un site web qui fonctionne en local avec le serveur embarqué de Django.
  • Ce site est accessible depuis les différents appareils du réseau local en tapant dans la fenêtre d’un navigateur web <local IP Raspberry>:<port serveur Django>/camera
  • Si vous ne souhaitez pas accéder au site depuis l’extérieur, vous pouvez, de manière peu orthodoxe, en rester là. Mais il est souhaitable de passer à l’étape suivante.

Prochaine étape

  • Installation d’un serveur Apache qui va prendre la main sur le serveur embarqué de Django.
  • Installation du module mod-wsgi, interface entre Apache et Django
  • Paramétrages de Apache et Django pour que le site soit accessible en production (et non plus en développement).