Installation Rapide
Ce tutoriel permet d’installer rapidement les éléments nécessaires sur la Raspberry.
On présuppose que :
- la Raspberry est fonctionnelle et mise à jour
- la Raspberry est accessible en ssh
- elle est dotée d’une adresse IP locale fixe
- le module PiTinfo est installé
- la téléinformation client est en mode standard (et non historique)
Les commandes sont lancées dans un terminal de la Raspberry.
Ce tutoriel est valide pour une installation en triphasé avec horaires jour/nuit. Les codes doivent être adaptés dans une configuration différente.
Installation des paquets et logiciels
- Installer les différents paquets : $ sudo apt install picocom nodejs npm
- Ouvrir le fichier /boot/firmware/config.txt : $ sudo nano /boot/firmware/config.txt
- Effacer son contenu
- Le remplacer par :/boot/firmware/config.txt
# For more options and information see # http://rptl.io/configtxt # Some settings may impact device functionality. See link above for details # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # Enable audio (loads snd_bcm2835) dtparam=audio=on # Additional overlays and parameters are documented # /boot/firmware/overlays/README # Automatically load overlays for detected cameras camera_auto_detect=1 # Automatically load overlays for detected DSI displays display_auto_detect=1 # Automatically load initramfs files, if found auto_initramfs=1 # Enable DRM VC4 V3D driver dtoverlay=vc4-kms-v3d max_framebuffers=2 # Don't have the firmware create an initial video= setting in cmdline.txt. # Use the kernel's default instead. disable_fw_kms_setup=1 # Run in 64-bit mode arm_64bit=1 # Disable compensation for displays with overscan disable_overscan=1 # Run as fast as firmware / board allows arm_boost=1 [cm4] # Enable host mode on the 2711 built-in XHCI USB controller. # This line should be removed if the legacy DWC2 controller is required # (e.g. for USB device mode) or if USB support is not required. otg_mode=1 [cm5] dtoverlay=dwc2,dr_mode=host [all] #enable_uart=0 enable_uart=1 #ajout pour lecture linky dtoverlay=disable-bt# For more options and information see # http://rptl.io/configtxt # Some settings may impact device functionality. See link above for details # Uncomment some or all of these to enable the optional hardware interfaces #dtparam=i2c_arm=on #dtparam=i2s=on #dtparam=spi=on # Enable audio (loads snd_bcm2835) dtparam=audio=on # Additional overlays and parameters are documented # /boot/firmware/overlays/README # Automatically load overlays for detected cameras camera_auto_detect=1 # Automatically load overlays for detected DSI displays display_auto_detect=1 # Automatically load initramfs files, if found auto_initramfs=1 # Enable DRM VC4 V3D driver dtoverlay=vc4-kms-v3d max_framebuffers=2 # Don't have the firmware create an initial video= setting in cmdline.txt. # Use the kernel's default instead. disable_fw_kms_setup=1 # Run in 64-bit mode arm_64bit=1 # Disable compensation for displays with overscan disable_overscan=1 # Run as fast as firmware / board allows arm_boost=1 [cm4] # Enable host mode on the 2711 built-in XHCI USB controller. # This line should be removed if the legacy DWC2 controller is required # (e.g. for USB device mode) or if USB support is not required. otg_mode=1 [cm5] dtoverlay=dwc2,dr_mode=host [all] #enable_uart=0 enable_uart=1 #ajout pour lecture linky dtoverlay=disable-bt
- Créer le dossier djangoTIC : $ mkdir -p ~/djangoTIC
- Créer l’environnement virtuel : $ python3 -m venv ~/djangoTIC/venv
- Se mettre en environnement virtuel : $ source ~/django/venv/bin/activate
- Installer Django : $ python -m pip install django
- Aller dans ~/djangoTIC : $ cd ~/djangoTIC
- Créer le projet ticServer : $ django-admin startproject ticServer
- Aller dans ~/djangoTIC/ticServer : $ cd ~/djangoTIC/ticServer
- Créer l’application ticapp : $ python manage.py startapp ticapp
- Créer les différents dossiers : $ mkdir -p ~/djangoTIC/ticServer/ticapp/templates ~/djangoTIC/ticServer/ticapp/management/commands ~/djangoTIC/ticServer/ticapp/static/src ~/djangoTIC/ticServer/ticapp/static/images
- Initialiser les modules python :
$ touch djangoTIC/ticServer/ticapp/management/__init__.py
$ touch djangoTIC/ticServer/ticapp/management/commands/__init__.py - Installer tailwind et flowbite : $ npm install tailwindcss @tailwindcss/cli flowbite
- Copier flowbite vers static : $ cp -r ~djangoTIC/ticServer/node_modules/flowbite ~djangoTIC/ticServer/ticapp/static/
- Créer le fichier input.css : $ nano ~/djangoTIC/ticServer/ticapp/static/src/input.css
- Copier/coller le contenu :static/src/input.css
@import "tailwindcss"; @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); @import "flowbite/src/themes/default"; @plugin "flowbite/plugin"; @source "../flowbite";@import "tailwindcss"; @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); @import "flowbite/src/themes/default"; @plugin "flowbite/plugin"; @source "../flowbite"; - Installer pyserial : $ pip install pyserial
- Installer gunicorn : $ pip install gunicorn
- Installer whitenoise : $ pip install whitenoise
- Installer python-decouple : $ pip install python-decouple
Création du site
models.py - views.py - urls.py
- Modifier models.py : $ nano ~/djangoTIC/ticServer/ticapp/models.py
- Effacer le contenu puis copier/coller :ticServer/ticapp/models.py
from django.db import models class Data(models.Model): dateTime = models.DateTimeField(auto_now_add=True, db_index=True) # la date et l'heure données par l'ordinateur date = models.CharField(max_length=13,blank=True, null=True) # la date et l'heure données par le TIC ltarf = models.CharField(max_length=16,blank=True, null=True) # Type de tarif en cours east = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur Consommation totale easf01 = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur index 1 Consommation heures creuses easf02 = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur index 2 Consommation heures pleines easd01 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 1 easd02 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 2 easd03 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 3 easd04 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 4 sinsts = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée sinsts1 = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée phase 1 sinsts2 = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée phase 2 sinsts3 = models.IntegerField(blank=True, null=True) # Puissance apparentefrom django.db import models class Data(models.Model): dateTime = models.DateTimeField(auto_now_add=True, db_index=True) # la date et l'heure données par l'ordinateur date = models.CharField(max_length=13,blank=True, null=True) # la date et l'heure données par le TIC ltarf = models.CharField(max_length=16,blank=True, null=True) # Type de tarif en cours east = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur Consommation totale easf01 = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur index 1 Consommation heures creuses easf02 = models.IntegerField(blank=True, null=True) # Energie active soutirée Fournisseur index 2 Consommation heures pleines easd01 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 1 easd02 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 2 easd03 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 3 easd04 = models.IntegerField(blank=True, null=True) # Energie active soutirée Distributeur index 4 sinsts = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée sinsts1 = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée phase 1 sinsts2 = models.IntegerField(blank=True, null=True) # Puissance apparente instantanée soutirée phase 2 sinsts3 = models.IntegerField(blank=True, null=True) # Puissance apparente - Créer le fichier utils.py : $ nano ~/djangoTIC/ticServer/ticapp/utils.py
- Copier/coller le contenu :ticServer/ticapp/utils.py
from .models import Data def formatNumber(nb): return '{:.3f}'.format(nb).replace(',', ' ').replace('.', ',') def conso(dateStart, dateEnd): query = Data.objects.filter(dateTime__range=(dateStart, dateEnd)).order_by('id').values("dateTime", "date","east", "easf01", "easf02") queryStart = query[0] queryEnd = query.reverse()[0] kWH = formatNumber((queryEnd["east"] - queryStart["east"])/1000) kWHCreux = formatNumber((queryEnd["easf01"] - queryStart["easf01"])/1000) kWHPlein = formatNumber((queryEnd["easf02"] - queryStart["easf02"])/1000) linkyStart = queryStart["date"] linkyEnd = queryEnd["date"] deltaTime = dateEnd - dateStart days = deltaTime.days seconds_remaining = deltaTime.seconds hours_remaining = seconds_remaining // 3600 minutes_remaining = (seconds_remaining % 3600) // 60 seconds_remaining = seconds_remaining % 60 dico = { "kWH": kWH, "kWHCreux": kWHCreux, "kWHPlein": kWHPlein, "dateStart": dateStart, "dateEnd": dateEnd, "linkyStart": linkyStart, "linkyEnd": linkyEnd, "deltaTime": deltaTime, "days": days, "hours": hours_remaining, "minutes": minutes_remaining, "seconds": seconds_remaining, } return dicofrom .models import Data def formatNumber(nb): return '{:.3f}'.format(nb).replace(',', ' ').replace('.', ',') def conso(dateStart, dateEnd): query = Data.objects.filter(dateTime__range=(dateStart, dateEnd)).order_by('id').values("dateTime", "date","east", "easf01", "easf02") queryStart = query[0] queryEnd = query.reverse()[0] kWH = formatNumber((queryEnd["east"] - queryStart["east"])/1000) kWHCreux = formatNumber((queryEnd["easf01"] - queryStart["easf01"])/1000) kWHPlein = formatNumber((queryEnd["easf02"] - queryStart["easf02"])/1000) linkyStart = queryStart["date"] linkyEnd = queryEnd["date"] deltaTime = dateEnd - dateStart days = deltaTime.days seconds_remaining = deltaTime.seconds hours_remaining = seconds_remaining // 3600 minutes_remaining = (seconds_remaining % 3600) // 60 seconds_remaining = seconds_remaining % 60 dico = { "kWH": kWH, "kWHCreux": kWHCreux, "kWHPlein": kWHPlein, "dateStart": dateStart, "dateEnd": dateEnd, "linkyStart": linkyStart, "linkyEnd": linkyEnd, "deltaTime": deltaTime, "days": days, "hours": hours_remaining, "minutes": minutes_remaining, "seconds": seconds_remaining, } return dico - Modifier views.py : $ nano ~/djangoTIC/ticServer/ticapp/views.py
- Effacer le contenu puis copier/coller :ticServer/ticapp/views.py
from django.shortcuts import render from django.utils import timezone from .models import Data from .utils import formatNumber, conso from datetime import timedelta def index(request): now = timezone.now() data = Data.objects.last() total = format(data.sinsts, ',').replace(',', ' ') phase1 = format(data.sinsts1, ',').replace(',', ' ') phase2 = format(data.sinsts2, ',').replace(',', ' ') phase3 = format(data.sinsts3, ',').replace(',', ' ') date = data.date creuxplein = data.ltarf values = { 'total': total, 'phase1': phase1, 'phase2': phase2, 'phase3': phase3, 'date': date, 'creuxplein': creuxplein, } context = { 'values': values, 'now': now, } return render(request, 'index.html', context) def jour(request): # new dateEnd = timezone.now() dateStart = timezone.localtime(dateEnd).replace( hour=0, minute=0, second=0, microsecond=0) values = conso(dateStart, dateEnd) context = {'values': values, } return render(request, "jour.html", context) def last24hours(request): # new values = conso(timezone.now() - timedelta(hours = 24), timezone.now()) context = {'values': values} return render(request, "last24hours.html", context) def hier(request): # new dateStart = timezone.localtime(timezone.now()).replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(hours=24) dateEnd = timezone.localtime(dateStart).replace(hour=23, minute=59, second=59, microsecond=999999) values = conso(dateStart, dateEnd) context = {'values': values, } return render(request, "hier.html", context) def lasthour(request): # new dateStart = timezone.now() - timedelta(hours = 1) dateEnd = timezone.now() values = conso(dateStart, dateEnd) context = {'values': values, 'dateStart': dateStart, 'dateEnd': dateEnd,} return render(request, "lasthour.html", context)from django.shortcuts import render from django.utils import timezone from .models import Data from .utils import formatNumber, conso from datetime import timedelta def index(request): now = timezone.now() data = Data.objects.last() total = format(data.sinsts, ',').replace(',', ' ') phase1 = format(data.sinsts1, ',').replace(',', ' ') phase2 = format(data.sinsts2, ',').replace(',', ' ') phase3 = format(data.sinsts3, ',').replace(',', ' ') date = data.date creuxplein = data.ltarf values = { 'total': total, 'phase1': phase1, 'phase2': phase2, 'phase3': phase3, 'date': date, 'creuxplein': creuxplein, } context = { 'values': values, 'now': now, } return render(request, 'index.html', context) def jour(request): # new dateEnd = timezone.now() dateStart = timezone.localtime(dateEnd).replace( hour=0, minute=0, second=0, microsecond=0) values = conso(dateStart, dateEnd) context = {'values': values, } return render(request, "jour.html", context) def last24hours(request): # new values = conso(timezone.now() - timedelta(hours = 24), timezone.now()) context = {'values': values} return render(request, "last24hours.html", context) def hier(request): # new dateStart = timezone.localtime(timezone.now()).replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(hours=24) dateEnd = timezone.localtime(dateStart).replace(hour=23, minute=59, second=59, microsecond=999999) values = conso(dateStart, dateEnd) context = {'values': values, } return render(request, "hier.html", context) def lasthour(request): # new dateStart = timezone.now() - timedelta(hours = 1) dateEnd = timezone.now() values = conso(dateStart, dateEnd) context = {'values': values, 'dateStart': dateStart, 'dateEnd': dateEnd,} return render(request, "lasthour.html", context) - Créer ticapp/urls.py : $ nano ~/djangoTIC/ticServer/ticapp/urls.py
- Copier/coller le contenu :ticServer/ticapp/urls.py
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), path('jour/', views.jour, name='jour'), path('lasthour/', views.lasthour, name='lasthour'), path('last24hours', views.last24hours, name='last24hours'), path('hier/', views.hier, name='hier'), ]from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), path('jour/', views.jour, name='jour'), path('lasthour/', views.lasthour, name='lasthour'), path('last24hours', views.last24hours, name='last24hours'), path('hier/', views.hier, name='hier'), ] - Modifier le fichier ticServer/urls.py : $ nano ~/djangoTIC/ticServer/ticServer/urls.py
- Effacer le contenu et le remplacer par :ticServer/ticServer/urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('ticapp.urls')), ]from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('ticapp.urls')), ]
Gabarits (templates)
- Créer le gabarit _base.html : $ nano ~/djangoTIC/ticServer/ticapp/templates/_base.html
- Copier/coller le contenu :ticapp/templates/_base.html
{% load static %} <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TIC Server</title> <link rel="stylesheet" href="{% static 'src/output.css' %}"> </head> <body class="bg-green-50"> {% include 'menu.html' %} <div class="container mx-auto mt-4"> {% block content %} {% endblock content %} </div> <script src="{% static 'flowbite/dist/flowbite.min.js' %}"></script> </body> </html>{% load static %} <!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TIC Server</title> <link rel="stylesheet" href="{% static 'src/output.css' %}"> </head> <body class="bg-green-50"> {% include 'menu.html' %} <div class="container mx-auto mt-4"> {% block content %} {% endblock content %} </div> <script src="{% static 'flowbite/dist/flowbite.min.js' %}"></script> </body> </html> - Créer le gabarit menu.html : $ nano ~/djangoTIC/ticServer/ticapp/templates/menu.html
- Copier/coller le contenu :ticapp/templates/menu.html
{% load static %} <nav class="bg-green-50 border-gray-200 px-2 sm:px-4 py-2.5 rounded dark:bg-gray-800"> <div class="container flex flex-wrap items-center justify-between mx-auto"> <a href="{{ .Site.Params.homepage }}/" class="flex items-center"> <img src="{% static 'images/linkylogo.png' %}" class="h-6 mr-3 sm:h-9" alt="Site Logo" /> <span class="self-center text-xl font-semibold whitespace-nowrap dark:text-white">TIC Serveur</span> </a> <button data-collapse-toggle="mobile-menu" type="button" class="inline-flex items-center p-2 ml-3 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="mobile-menu" aria-expanded="false"> <span class="sr-only">Open main menu</span> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg> <svg class="hidden w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg> </button> <div class="hidden w-full md:block md:w-auto" id="mobile-menu"> <ul class="flex flex-col mt-4 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium"> <li> <a href="{% url 'index' %}" class="block py-2 pl-3 pr-4 text-white bg-zinc-400 rounded md:bg-transparent md:text-green-700 md:p-0 dark:text-white" aria-current="page">Accueil</a> </li> <li> <a href="{% url 'jour' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">Jour</a> </li> <li> <a href="{% url 'lasthour' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">Dernière Heure</a> </li> <li> <a href="{% url 'last24hours' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">24 heures</a> </li> <li> <a href="{% url 'hier' %}" class="block py-2 pl-3 pr-4 text-gray-700 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Hier</a> </li> </ul> </div> </div> </nav>{% load static %} <nav class="bg-green-50 border-gray-200 px-2 sm:px-4 py-2.5 rounded dark:bg-gray-800"> <div class="container flex flex-wrap items-center justify-between mx-auto"> <a href="{{ .Site.Params.homepage }}/" class="flex items-center"> <img src="{% static 'images/linkylogo.png' %}" class="h-6 mr-3 sm:h-9" alt="Site Logo" /> <span class="self-center text-xl font-semibold whitespace-nowrap dark:text-white">TIC Serveur</span> </a> <button data-collapse-toggle="mobile-menu" type="button" class="inline-flex items-center p-2 ml-3 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="mobile-menu" aria-expanded="false"> <span class="sr-only">Open main menu</span> <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg> <svg class="hidden w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg> </button> <div class="hidden w-full md:block md:w-auto" id="mobile-menu"> <ul class="flex flex-col mt-4 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium"> <li> <a href="{% url 'index' %}" class="block py-2 pl-3 pr-4 text-white bg-zinc-400 rounded md:bg-transparent md:text-green-700 md:p-0 dark:text-white" aria-current="page">Accueil</a> </li> <li> <a href="{% url 'jour' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">Jour</a> </li> <li> <a href="{% url 'lasthour' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">Dernière Heure</a> </li> <li> <a href="{% url 'last24hours' %}" class="block py-2 pl-3 pr-4 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700">24 heures</a> </li> <li> <a href="{% url 'hier' %}" class="block py-2 pl-3 pr-4 text-gray-700 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-green-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Hier</a> </li> </ul> </div> </div> </nav> - Télécharger l’image “linkylogo.png” : $ wget -O ~/djangoTIC/ticServer/ticapp/static/images/linkylogo.png https://linky-tuto.netlify.app/images/linkylogo.png
- Créer le gabarit index.html : $ nano djangoTIC/ticServer/ticapp/templates/index.html
- Copier/coller le contenu :ticapp/templates/index.html
{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Puissance Instantanée (en Watt) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ now | date:" D j F Y - H:i:s "}}</p> <p class="text-gray-400 pl-4"></p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="text-gray-400 ">Date du TIC : {{ values.date }}</p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="text-gray-400 ">{{ values.creuxplein }}</p> </div> {% endtimezone %} <div class="flex items-center justify-center pt-2 md:pt-4"> <table class="border-separate border-spacing-x-8 md:border-spacing-x-16 border-spacing-y-4 md:border-spacing-y-8 border border-gray-200"> <tbody> <tr class=""> <td class="font-semibold ">Total 3 phases</td> <td class="font-semibold text-right ">{{ values.total }}</td> </tr> <tr> <td class="">Phase 1</td> <td class="text-right">{{ values.phase1 }}</td> </tr> <tr> <td class="">Phase 2</td> <td class="text-right">{{ values.phase2 }}</td> </tr> <tr> <td class="">Phase 3</td> <td class="text-right">{{ values.phase3 }}</td> </tr> </tbody> </table> </div> <script> setTimeout(function(){ window.location.reload(1); }, 5000); </script> {% endblock content %}{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Puissance Instantanée (en Watt) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ now | date:" D j F Y - H:i:s "}}</p> <p class="text-gray-400 pl-4"></p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="text-gray-400 ">Date du TIC : {{ values.date }}</p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="text-gray-400 ">{{ values.creuxplein }}</p> </div> {% endtimezone %} <div class="flex items-center justify-center pt-2 md:pt-4"> <table class="border-separate border-spacing-x-8 md:border-spacing-x-16 border-spacing-y-4 md:border-spacing-y-8 border border-gray-200"> <tbody> <tr class=""> <td class="font-semibold ">Total 3 phases</td> <td class="font-semibold text-right ">{{ values.total }}</td> </tr> <tr> <td class="">Phase 1</td> <td class="text-right">{{ values.phase1 }}</td> </tr> <tr> <td class="">Phase 2</td> <td class="text-right">{{ values.phase2 }}</td> </tr> <tr> <td class="">Phase 3</td> <td class="text-right">{{ values.phase3 }}</td> </tr> </tbody> </table> </div> <script> setTimeout(function(){ window.location.reload(1); }, 5000); </script> {% endblock content %} - Créer le gabarit consommation.html : $ nano djangoTIC/ticServer/ticapp/templates/consommation.html
- Copier/coller le contenu :ticapp/templates/consommation.html
<div class="flex items-center justify-center pt-2 md:pt-4"> <table class="border-separate border-spacing-x-8 md:border-spacing-x-16 border-spacing-y-4 md:border-spacing-y-8 border border-gray-200"> <tbody> <tr> <td>Total</td> <td class="text-right">{{ values.kWH }}</td> </tr> <tr> <td>Heures Creuses</td> <td class="text-right">{{ values.kWHCreux }}</td> </tr> <tr> <td>Heures Pleines</td> <td class="text-right">{{ values.kWHPlein }}</td> </tr> </tbody> </table> </div><div class="flex items-center justify-center pt-2 md:pt-4"> <table class="border-separate border-spacing-x-8 md:border-spacing-x-16 border-spacing-y-4 md:border-spacing-y-8 border border-gray-200"> <tbody> <tr> <td>Total</td> <td class="text-right">{{ values.kWH }}</td> </tr> <tr> <td>Heures Creuses</td> <td class="text-right">{{ values.kWHCreux }}</td> </tr> <tr> <td>Heures Pleines</td> <td class="text-right">{{ values.kWHPlein }}</td> </tr> </tbody> </table> </div> - Créer le gabarit jour.html : $ nano djangoTIC/ticServer/ticapp/templates/jour.html
- Copier/coller le contenu :ticapp/templates/jour.html
{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Consommation du Jour (en kWh) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ values.dateEnd | date:" D j F Y "}} de minuit à {{ values.dateEnd | date:" H:i "}} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Durée : {{ values.hours }} heures {{ values.minutes }} minutes {{ values.seconds }} secondes</p> </div> {% endtimezone %} {% localize on %} {% include "consommation.html" %} {% endlocalize %}{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Consommation du Jour (en kWh) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ values.dateEnd | date:" D j F Y "}} de minuit à {{ values.dateEnd | date:" H:i "}} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Durée : {{ values.hours }} heures {{ values.minutes }} minutes {{ values.seconds }} secondes</p> </div> {% endtimezone %} {% localize on %} {% include "consommation.html" %} {% endlocalize %} - Créer le gabarit lasthour.html : $ nano djangoTIC/ticServer/ticapp/templates/lasthour.html
- Copier/coller le contenu :ticapp/templates/lasthour.html
{% extends "_base.html" %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Dernière heure (en kWh) </h1> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ dateStart | date:" D j F Y "}} de {{ dateStart | date:" H:i:s "}} à {{ dateEnd | date:" H:i:s "}} </p> </div> {% include "consommation.html" %} {% endblock content %}{% extends "_base.html" %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Dernière heure (en kWh) </h1> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ dateStart | date:" D j F Y "}} de {{ dateStart | date:" H:i:s "}} à {{ dateEnd | date:" H:i:s "}} </p> </div> {% include "consommation.html" %} {% endblock content %} - Créer le gabarit last24hours.html : $ nano ~/djangoTIC/ticServer/ticapp/templates/last24hours.html
- Copier/coller le contenu :ticapp/templates/last24thours.html
{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} {% timezone "Europe/Paris" %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Dernières 24 heures (en kWh) </h1> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500"> Heure : {{ values.dateEnd | date:"H:i:s"}}</p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p>du {{ values.dateStart | date:"l j F Y"}} au {{ values.dateEnd | date:"l j F Y"}} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> {% endtimezone %} {% include "consommation.html" %} {% endblock content %}{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} {% timezone "Europe/Paris" %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Dernières 24 heures (en kWh) </h1> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500"> Heure : {{ values.dateEnd | date:"H:i:s"}}</p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p>du {{ values.dateStart | date:"l j F Y"}} au {{ values.dateEnd | date:"l j F Y"}} </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> {% endtimezone %} {% include "consommation.html" %} {% endblock content %} - Créer le gabarit hier.html : $ nano ~/djangoTIC/ticServer/ticapp/templates/hier.html
- Copier/coller le contenu :ticapp/templates/hier.html
{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Consommation de la Veille (en kWh) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ values.dateStart | date:" l j F Y "}} <br><br>de minuit à 23h59mn59s </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> {% endtimezone %} {% include "consommation.html" %} {% endblock content %}{% extends "_base.html" %} {% load l10n %} {% load tz %} {% block content %} <div class="max-w-3xl mx-auto text-center mt-12"> <h1 class="text-xl md:text-3xl lg:text-4xl font-bold text-gray-700 leading-tight mb-2 border-b-2 border-gray-400 pb-2"> Consommation de la Veille (en kWh) </h1> </div> {% timezone "Europe/Paris" %} <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-semibold text-gray-500">{{ values.dateStart | date:" l j F Y "}} <br><br>de minuit à 23h59mn59s </p> </div> <div class="flex items-center justify-center pt-2 md:pt-4"> <p class="font-medium text-gray-500">Horaires LINKY : {{ values.linkyStart }} / {{ values.linkyEnd }} </p> </div> {% endtimezone %} {% include "consommation.html" %} {% endblock content %}
Commandes et services
- Créer la commande capture_tic : $ nano ~/djangoTIC/ticServer/ticapp/management/commands/capture_tic.py
- Copier/coller le contenu :management/commands/capture_tic.py
from django.core.management.base import BaseCommand from ticapp.models import Data from django.utils import timezone import serial import time class Command(BaseCommand): help = 'Capture et insère les données TIC en continu depuis le compteur Linky' def __init__(self): super().__init__() # Initialisation du port série self.ser = serial.Serial( port="/dev/ttyAMA0", baudrate=9600, bytesize=serial.SEVENBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1, xonxoff=False, rtscts=False ) self.listItems = ["DATE", "LTARF", "EAST", "EASF01", "EASF02", "EASD01", "EASD02", "EASD03", "EASD04", "SINSTS", "SINSTS1", "SINSTS2", "SINSTS3"] def checkIfDictFull(self, dict, listItems): """Vérifie si un dictionnaire contient toutes les clés qui sont dans la liste listItems""" setKeys = set(dict.keys()) return set(listItems).issubset(setKeys) def capture_trame(self): """Capture une trame TIC complète""" while True: if self.ser.read(1) == b'\x02': # Début de trame trame = b'\x02' while True: byte = self.ser.read(1) trame += byte if byte == b'\x03': # Fin de trame return trame def parse_trame(self, trame): """Parse la trame et retourne un dictionnaire avec les données""" try: data = trame[1:-1].decode('ascii', errors='ignore') lines = data.split('\r\n') dico = {} for line in lines: if '\t' in line: parts = line.split('\t') key = parts[0] value = parts[1] if len(parts) > 1 else '' dico[key] = value # Ne retourner que si toutes les clés nécessaires sont présentes if self.checkIfDictFull(dico, self.listItems): subDico = {key: dico[key] for key in self.listItems if key in dico} return subDico else: return None except Exception as e: self.stderr.write(self.style.ERROR(f'Erreur de parsing: {e}')) return None def handle(self, *args, **options): self.stdout.write(self.style.SUCCESS('=== Démarrage de la capture TIC ===')) self.stdout.write(f'Port série: {self.ser.port}') self.stdout.write(f'Baudrate: {self.ser.baudrate}') compteur = 0 erreurs = 0 try: while True: # Capture de la trame trame = self.capture_trame() # Parse de la trame donnees = self.parse_trame(trame) if donnees: try: # Insertion dans la base de données Data.objects.create( date=donnees["DATE"][1:], # Retire le premier caractère larf=donnees["LTARF"], east=donnees["EAST"], easf01=donnees["EASF01"], easf02=donnees["EASF02"], easd01=donnees["EASD01"], easd02=donnees["EASD02"], easd03=donnees["EASD03"], easd04=donnees["EASD04"], sinsts=donnees["SINSTS"], sinsts1=donnees["SINSTS1"], sinsts2=donnees["SINSTS2"], sinsts3=donnees["SINSTS3"] ) compteur += 1 erreurs = 0 # Reset du compteur d'erreurs # Log périodique if compteur % 100 == 0: self.stdout.write( self.style.SUCCESS( f'✓ {compteur} enregistrements insérés - ' f'Dernier: {timezone.now().strftime("%H:%M:%S")}' ) ) except Exception as e: erreurs += 1 self.stderr.write( self.style.ERROR(f'Erreur insertion BD: {e}') ) if erreurs > 10: self.stderr.write( self.style.ERROR('Trop d\'erreurs consécutives, arrêt') ) break else: # Trame incomplète, on continue sans erreur pass time.sleep(0.5) # Petite pause entre les captures except KeyboardInterrupt: self.stdout.write( self.style.WARNING( f'\n=== Arrêt demandé par l\'utilisateur ===\n' f'Total enregistrements: {compteur}' ) ) except Exception as e: self.stderr.write(self.style.ERROR(f'Erreur fatale: {e}')) finally: # Fermeture propre du port série if self.ser.is_open: self.ser.close() self.stdout.write('Port série fermé')from django.core.management.base import BaseCommand from ticapp.models import Data from django.utils import timezone import serial import time class Command(BaseCommand): help = 'Capture et insère les données TIC en continu depuis le compteur Linky' def __init__(self): super().__init__() # Initialisation du port série self.ser = serial.Serial( port="/dev/ttyAMA0", baudrate=9600, bytesize=serial.SEVENBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1, xonxoff=False, rtscts=False ) self.listItems = ["DATE", "LTARF", "EAST", "EASF01", "EASF02", "EASD01", "EASD02", "EASD03", "EASD04", "SINSTS", "SINSTS1", "SINSTS2", "SINSTS3"] def checkIfDictFull(self, dict, listItems): """Vérifie si un dictionnaire contient toutes les clés qui sont dans la liste listItems""" setKeys = set(dict.keys()) return set(listItems).issubset(setKeys) def capture_trame(self): """Capture une trame TIC complète""" while True: if self.ser.read(1) == b'\x02': # Début de trame trame = b'\x02' while True: byte = self.ser.read(1) trame += byte if byte == b'\x03': # Fin de trame return trame def parse_trame(self, trame): """Parse la trame et retourne un dictionnaire avec les données""" try: data = trame[1:-1].decode('ascii', errors='ignore') lines = data.split('\r\n') dico = {} for line in lines: if '\t' in line: parts = line.split('\t') key = parts[0] value = parts[1] if len(parts) > 1 else '' dico[key] = value # Ne retourner que si toutes les clés nécessaires sont présentes if self.checkIfDictFull(dico, self.listItems): subDico = {key: dico[key] for key in self.listItems if key in dico} return subDico else: return None except Exception as e: self.stderr.write(self.style.ERROR(f'Erreur de parsing: {e}')) return None def handle(self, *args, **options): self.stdout.write(self.style.SUCCESS('=== Démarrage de la capture TIC ===')) self.stdout.write(f'Port série: {self.ser.port}') self.stdout.write(f'Baudrate: {self.ser.baudrate}') compteur = 0 erreurs = 0 try: while True: # Capture de la trame trame = self.capture_trame() # Parse de la trame donnees = self.parse_trame(trame) if donnees: try: # Insertion dans la base de données Data.objects.create( date=donnees["DATE"][1:], # Retire le premier caractère larf=donnees["LTARF"], east=donnees["EAST"], easf01=donnees["EASF01"], easf02=donnees["EASF02"], easd01=donnees["EASD01"], easd02=donnees["EASD02"], easd03=donnees["EASD03"], easd04=donnees["EASD04"], sinsts=donnees["SINSTS"], sinsts1=donnees["SINSTS1"], sinsts2=donnees["SINSTS2"], sinsts3=donnees["SINSTS3"] ) compteur += 1 erreurs = 0 # Reset du compteur d'erreurs # Log périodique if compteur % 100 == 0: self.stdout.write( self.style.SUCCESS( f'✓ {compteur} enregistrements insérés - ' f'Dernier: {timezone.now().strftime("%H:%M:%S")}' ) ) except Exception as e: erreurs += 1 self.stderr.write( self.style.ERROR(f'Erreur insertion BD: {e}') ) if erreurs > 10: self.stderr.write( self.style.ERROR('Trop d\'erreurs consécutives, arrêt') ) break else: # Trame incomplète, on continue sans erreur pass time.sleep(0.5) # Petite pause entre les captures except KeyboardInterrupt: self.stdout.write( self.style.WARNING( f'\n=== Arrêt demandé par l\'utilisateur ===\n' f'Total enregistrements: {compteur}' ) ) except Exception as e: self.stderr.write(self.style.ERROR(f'Erreur fatale: {e}')) finally: # Fermeture propre du port série if self.ser.is_open: self.ser.close() self.stdout.write('Port série fermé') - Créer le service django-ticserver : $ sudo nano /etc/systemd/system/django-ticserver.service
- Copier/coller le contenu :/etc/systemd/system/django-ticserver.service
[Unit] Description=Django TIC Web Server After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/djangoTIC/ticServer Environment="PATH=/home/pi/djangoTIC/venv/bin" ExecStart=/home/pi/djangoTIC/venv/bin/gunicorn --bind 0.0.0.0:8000 --workers 2 ticServer.wsgi:application Restart=always RestartSec=10 [Install] WantedBy=multi-user.target[Unit] Description=Django TIC Web Server After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/djangoTIC/ticServer Environment="PATH=/home/pi/djangoTIC/venv/bin" ExecStart=/home/pi/djangoTIC/venv/bin/gunicorn --bind 0.0.0.0:8000 --workers 2 ticServer.wsgi:application Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
- Créer le service tic-capture : $ sudo nano /etc/systemd/system/django-ticserver.service
- Copier/coller le contenu :/etc/systemd/system/tic-capture.service
[Unit] Description=Capture des données TIC Linky After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/djangoTIC/ticServer ExecStart=/home/pi/djangoTIC/venv/bin/python manage.py capture_tic Restart=always RestartSec=10 [Install] WantedBy=multi-user.target[Unit] Description=Capture des données TIC Linky After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/djangoTIC/ticServer ExecStart=/home/pi/djangoTIC/venv/bin/python manage.py capture_tic Restart=always RestartSec=10 [Install] WantedBy=multi-user.target
- Lancer les services :
$ sudo systemctl daemon-reload
$ sudo systemctl enable django-ticserver
$ sudo systemctl start django-ticserver
$ sudo systemctl enable tic-capture
$ sudo systemctl start tic-capture
Mise en production
- Créer une clé de sécurité : $ python -c ‘from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())’
- Créer un fichier .env : $ nano ~/djangoTIC/ticServer/.env
- Écrire son contenu en l’adaptant :djangoTIC/ticServer/.env
SECRET_KEY=votre-cle-generee-ici DEBUG=False ALLOWED_HOSTS=192.168.x.x,localhostSECRET_KEY=votre-cle-generee-ici DEBUG=False ALLOWED_HOSTS=192.168.x.x,localhost
- Ouvrir settings.py : $ nano ~/djangoTIC/ticServer/ticServer/settings.py
- Effacer son contenu et le remplacer par :ticServer/ticServer/settings.py
""" Django settings for ticServer project. Generated by 'django-admin startproject' using Django 5.1.7. For more information on this file, see https://docs.djangoproject.com/en/5.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.1/ref/settings/ """ from pathlib import Path import os from decouple import Config, RepositoryEnv #pour la production et le masquage des données # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Spécification du chemin exact de .env config = Config(RepositoryEnv(BASE_DIR / '.env')) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = config('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')]) # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'ticapp.apps.TicappConfig', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'ticServer.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'ticServer.wsgi.application' # Database # https://docs.djangoproject.com/en/5.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', 'TIME_ZONE': 'Europe/Paris', } } # Password validation # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/5.1/topics/i18n/ LANGUAGE_CODE = 'fr' TIME_ZONE = 'Europe/Paris' USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.1/howto/static-files/ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", }, } # Default primary key field type # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'""" Django settings for ticServer project. Generated by 'django-admin startproject' using Django 5.1.7. For more information on this file, see https://docs.djangoproject.com/en/5.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.1/ref/settings/ """ from pathlib import Path import os from decouple import Config, RepositoryEnv #pour la production et le masquage des données # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Spécification du chemin exact de .env config = Config(RepositoryEnv(BASE_DIR / '.env')) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = config('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')]) # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'ticapp.apps.TicappConfig', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'ticServer.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'ticServer.wsgi.application' # Database # https://docs.djangoproject.com/en/5.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', 'TIME_ZONE': 'Europe/Paris', } } # Password validation # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/5.1/topics/i18n/ LANGUAGE_CODE = 'fr' TIME_ZONE = 'Europe/Paris' USE_I18N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.1/howto/static-files/ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", }, } # Default primary key field type # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - Lancer le css (Vérifier de bien être dans ~/djangoTIC/ticServer) : $ npx @tailwindcss/cli -i ticapp/static/src/input.css -o ticapp/static/src/output.css --minify
- Effectuer les migrations :
$ python ~/djangotTIC/ticServer/manage.py makemigrations
$ python ~/djangotTIC/ticServer/manage.py migrate - Reconfigurer les fichiers statiques : $ python ~/djangotTIC/ticServer/manage.py collectstatic –noinput
- Rebouter la Raspberry : $ sudo reboot
- Sauf erreur ou omission, le site est visible à l’adresse 192.168.x.x:8000