Outils pour utilisateurs

Outils du site


linux:rpi:installation

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
linux:rpi:installation [2025/04/26 16:37] tutospistolinux:rpi:installation [2025/05/11 10:16] (Version actuelle) tutospisto
Ligne 1: Ligne 1:
-Après avoir installé et mis à jour Raspberry pi OS ( [[Linux:Installation:SSH]], [[Linux:Installation:BashRc]], ), on va installer un client pour nextcloud, et un environnement python pour monter un poulailler connecté.+Après avoir installé et mis à jour Raspberry pi OS ( [[Linux:Installation:SSH]], [[Linux:Installation:BashRc]], [[Linux:Installation:PHP]]), on va installer un client pour nextcloud, et un environnement python pour monter un poulailler connecté.
  
 ====== Nextcloud CMD ====== ====== Nextcloud CMD ======
Ligne 7: Ligne 7:
 https://www.aukfood.fr/nextcloud-client-en-ligne-de-commande/ https://www.aukfood.fr/nextcloud-client-en-ligne-de-commande/
  
-<code bash>sudo apt-get install nextcloud-client</code> ne trouve pas le client. +<code bash>sudo apt install nextcloud-client</code> ne trouve pas le client. 
  
 Il faut ajouter le dépôt https://ppa.launchpadcontent.net/nextcloud-devs Il faut ajouter le dépôt https://ppa.launchpadcontent.net/nextcloud-devs
-<code bash> +<code bash>sudo apt install software-properties-common python3-launchpadlib</code>
-sudo apt-get install software-properties-common +
-sudo apt-get install  python3-launchpadlib +
-</code>+
  
 Ensuite on peut faire l'installation du dépôt et de sa clé GPG : Ensuite on peut faire l'installation du dépôt et de sa clé GPG :
Ligne 21: Ligne 18:
  
 <code bash>sudo nano /etc/apt/sources.list.d/nextcloud-devs-ubuntu-client-bookworm.list</code> <code bash>sudo nano /etc/apt/sources.list.d/nextcloud-devs-ubuntu-client-bookworm.list</code>
 +Et modifier la ligne en :
 <code bash>deb https://ppa.launchpadcontent.net/nextcloud-devs/client/ubuntu/ jammy main</code> <code bash>deb https://ppa.launchpadcontent.net/nextcloud-devs/client/ubuntu/ jammy main</code>
  
 Et enfin faire l'installation de nextcloud-client : Et enfin faire l'installation de nextcloud-client :
  
-<code bash>sudo apt-get install nextcloud-client</code>+<code bash> 
 +sudo apt update 
 +sudo apt install nextcloud-client</code>
  
 On peut procéder à une première synchronisation :  On peut procéder à une première synchronisation : 
Ligne 33: Ligne 33:
 on peut ajouter --non-interactive pour une utilisation dans un cron par exemple. on peut ajouter --non-interactive pour une utilisation dans un cron par exemple.
  
-nextcloudcmd --path /<Directory_that_has_been_created> /home/user/<my_sync_folder> \ https://<username>:<secret>@<server_address>+<code bash>nextcloudcmd --path /<Directory_that_has_been_created> /home/user/<my_sync_folder> \ https://<username>:<secret>@<server_address></code> 
 + 
 + 
  
 ====== Python ====== ====== Python ======
 +
 +<code bash>sudo apt install python3 python3-dev python3-rpi.gpio python3-venv</code>
 +
 +
 +Python fonctionne avec des environnement (par projet ou par user). On crée un utilisateur dédié :
 +<code bash>sudo useradd -m -d /home/$USER $USER
 +sudo passwd $USER
 +cd /home/$USER</code>
 +
 +Puis l'environnement :
 +<code bash>python3 -m venv .venv</code>
 +
 +On l'active :
 +<code bash>source /home/pi/.venv/bin/activate</code>
 +
 +Dans l'environnement .venv : 
 +<code bash>
 +#pip3 install RPi (n'a pas marché ? non nécessaire ?)
 +pip3 install RPi.GPIO
 +#pip3 install Adafruit_DHT --install-option="--force-pi" (on va essayer de se passer de cette lib obsolète et buguée)
 +pip3 install board</code>
 +
 +Et enfin pour lancer un script (potentiellement en sudo) : 
 +<code bash>/home/$USER/.venv/bin/python3 /home/$USER/script.py</code>
 +
 +Si les pages php n'arrivent pas à executer le script python, cela peut provenir d'un problème de droits.
 +On peut ajouter www-data au sudoers :
 +<code bash>sudo nano /etc/sudoers</code>
 +Ajouter à la fin la ligne :
 +<code bash>www-data  ALL = NOPASSWD: ALL</code>
 +
 +====== DHT22 ======
 +
 +
 +Actuellement avec le code trouvé ici : https://www.reddit.com/r/raspberry_pi/comments/13pscin/comment/jlbinb2/?share_id=wWvKIpI7UVC945M2GZ5BK&utm_medium=android_app&utm_name=androidcss&utm_source=share&utm_term=1
 +
 +Et dont voici le script : 
 +<hidden script python DHT >
 +<code bash dht.py[enable_line_numbers=1, start_line_numbers_at=1, skin="sons-of-obsidian"]>
 +# MIT License
 +
 +# Original author: Zoltan Szarvas
 +# https://github.com/szazo/DHT11_Python
 +
 +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 +
 +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 +
 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 +
 +
 +#!/usr/bin/python3
 +import time
 +import sys
 +import RPi.GPIO as GPIO
 +
 +# DHTxx sensor result returned by DHT.read() method'
 +class DHTResult:
 +    
 +
 +    ERR_NO_ERROR = 0
 +    ERR_MISSING_DATA = 1
 +    ERR_CRC = 2
 +    ERR_NOT_FOUND = 3
 +
 +    error_code = ERR_NO_ERROR
 +    temperature = -1
 +    humidity = -1     
 +
 +    def __init__(self, error_code, temperature, humidity):
 +        self.error_code = error_code
 +        self.temperature = temperature
 +        self.humidity = humidity
 +                                
 +
 +    def is_valid(self):
 +        return self.error_code == DHTResult.ERR_NO_ERROR
 +        
 +    
 +    
 +# DHTxx sensor reader class for Raspberry'
 +class DHT:
 +    
 +    __pin = 0
 +    __isDht11 = True
 +
 +    def __init__(self, pin, isDht11):
 +        self.__pin = pin
 +        self.__isDht11 = isDht11
 +
 +    def read(self):
 +        GPIO.setup(self.__pin, GPIO.OUT)
 +
 +        # send initial high
 +        self.__send_and_sleep(GPIO.HIGH, 0.05)
 +
 +        # pull down to low
 +        self.__send_and_sleep(GPIO.LOW, 0.02)
 +
 +        # change to input using pull up
 +        GPIO.setup(self.__pin, GPIO.IN, GPIO.PUD_UP)
 +
 +        # collect data into an array
 +        data = self.__collect_input()
 +
 +        # parse lengths of all data pull up periods
 +        pull_up_lengths = self.__parse_data_pull_up_lengths(data)
 +        
 +        if len(pull_up_lengths) == 0:
 +            return DHTResult(DHTResult.ERR_NOT_FOUND, 0, 0)
 +
 +        # if bit count mismatch, return error (4 byte data + 1 byte checksum)
 +        if len(pull_up_lengths) != 40:
 +            return DHTResult(DHTResult.ERR_MISSING_DATA, 0, 0)
 +
 +        # calculate bits from lengths of the pull up periods
 +        bits = self.__calculate_bits(pull_up_lengths)
 +
 +        # we have the bits, calculate bytes
 +        the_bytes = self.__bits_to_bytes(bits)
 +
 +        # calculate checksum and check
 +        checksum = self.__calculate_checksum(the_bytes)
 +        if the_bytes[4] != checksum:
 +            return DHTResult(DHTResult.ERR_CRC, 0, 0)
 +
 +        # ok, we have valid data
 +        # The meaning of the return sensor values
 +        # the_bytes[0]: humidity int
 +        # the_bytes[1]: humidity decimal
 +        # the_bytes[2]: temperature int
 +        # the_bytes[3]: temperature decimal
 +        temperature = -1
 +        humidity = -1
 +        if(self.__isDht11):
 +            # DHT11
 +            temperature = the_bytes[2] + float(the_bytes[3]) / 10
 +            humidity = the_bytes[0] + float(the_bytes[1]) / 10
 +        else:
 +            #DHT22
 +            temperature = (the_bytes[2] * 256 + float(the_bytes[3])) / 10
 +            humidity = (the_bytes[0] * 256 + float(the_bytes[1])) / 10
 +            c = (float)(((the_bytes[2]&0x7F)<< 8)+the_bytes[3])/10
 +            
 +            if ( c > 125 ):
 +                c = the_bytes[2]
 +                
 +            if (the_bytes[2] & 0x80):
 +                c = -c;
 +            
 +            temperature = c
 +            humidity = ((the_bytes[0]<<8)+the_bytes[1])/10.00
 +
 +        return DHTResult(DHTResult.ERR_NO_ERROR, temperature, humidity)
 +                                                          
 +
 +    def __send_and_sleep(self, output, sleep):
 +        GPIO.output(self.__pin, output)
 +        time.sleep(sleep)
 +
 +    def __collect_input(self):
 +        # collect the data while unchanged found
 +        unchanged_count = 0
 +
 +        # this is used to determine where is the end of the data
 +        max_unchanged_count = 100
 +
 +        last = -1
 +        data = []
 +        while True:
 +            current = GPIO.input(self.__pin)
 +            data.append(current)
 +            if last != current:
 +                unchanged_count = 0
 +                last = current
 +            else:
 +                unchanged_count += 1
 +                if unchanged_count > max_unchanged_count:
 +                    break
 +
 +        return data
 +
 +    def __parse_data_pull_up_lengths(self, data):
 +        STATE_INIT_PULL_DOWN = 1
 +        STATE_INIT_PULL_UP = 2
 +        STATE_DATA_FIRST_PULL_DOWN = 3
 +        STATE_DATA_PULL_UP = 4
 +        STATE_DATA_PULL_DOWN = 5
 +
 +        state = STATE_INIT_PULL_DOWN
 +
 +        lengths = [] # will contain the lengths of data pull up periods
 +        current_length = 0 # will contain the length of the previous period
 +
 +        for i in range(len(data)):
 +
 +            current = data[i]
 +            current_length += 1
 +
 +            if state == STATE_INIT_PULL_DOWN:
 +                if current == GPIO.LOW:
 +                    # ok, we got the initial pull down
 +                    state = STATE_INIT_PULL_UP
 +                    continue
 +                else:
 +                    continue
 +            if state == STATE_INIT_PULL_UP:
 +                if current == GPIO.HIGH:
 +                    # ok, we got the initial pull up
 +                    state = STATE_DATA_FIRST_PULL_DOWN
 +                    continue
 +                else:
 +                    continue
 +            if state == STATE_DATA_FIRST_PULL_DOWN:
 +                if current == GPIO.LOW:
 +                    # we have the initial pull down, the next will be the data pull up
 +                    state = STATE_DATA_PULL_UP
 +                    continue
 +                else:
 +                    continue
 +            if state == STATE_DATA_PULL_UP:
 +                if current == GPIO.HIGH:
 +                    # data pulled up, the length of this pull up will determine whether it is 0 or 1
 +                    current_length = 0
 +                    state = STATE_DATA_PULL_DOWN
 +                    continue
 +                else:
 +                    continue
 +            if state == STATE_DATA_PULL_DOWN:
 +                if current == GPIO.LOW:
 +                    # pulled down, we store the length of the previous pull up period
 +                    lengths.append(current_length)
 +                    state = STATE_DATA_PULL_UP
 +                    continue
 +                else:
 +                    continue
 +
 +        return lengths
 +
 +    def __calculate_bits(self, pull_up_lengths):
 +        # find shortest and longest period
 +        shortest_pull_up = 1000
 +        longest_pull_up = 0
 +
 +        for i in range(0, len(pull_up_lengths)):
 +            length = pull_up_lengths[i]
 +            if length < shortest_pull_up:
 +                shortest_pull_up = length
 +            if length > longest_pull_up:
 +                longest_pull_up = length
 +
 +        # use the halfway to determine whether the period it is long or short
 +        halfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2
 +        bits = []
 +
 +        for i in range(0, len(pull_up_lengths)):
 +            bit = False
 +            if pull_up_lengths[i] > halfway:
 +                bit = True
 +            bits.append(bit)
 +
 +        return bits
 +
 +    def __bits_to_bytes(self, bits):
 +        the_bytes = []
 +        byte = 0
 +
 +        for i in range(0, len(bits)):
 +            byte = byte << 1
 +            if (bits[i]):
 +                byte = byte | 1
 +            else:
 +                byte = byte | 0
 +            if ((i + 1) % 8 == 0):
 +                the_bytes.append(byte)
 +                byte = 0
 +
 +        return the_bytes
 +
 +    def __calculate_checksum(self, the_bytes):
 +        return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +        
 +# Parse command line parameters
 +if len(sys.argv) == 3:
 +    sensor = sys.argv[1]
 +    if sensor not in ("11", "22", "2302"):
 +        print('Sensor "{}" is not valid. Use 11, 22 or 2302'.format(sensor))
 +        exit(1)
 +    isDht11 = sensor == "11"
 +    try:
 +        pin = int(sys.argv[2])
 +        if (pin < 2 or pin > 27):
 +            raise ValueError
 +    except:
 +        print('Gpio {} is not valid'.format(pin))
 +        exit(1)
 +else:
 +    print('usage: dht.py [11|22|2302] [gpio#]')
 +    exit(1)       
 +        
 +        
 +# initialize GPIO
 +GPIO.setwarnings(False)
 +GPIO.setmode(GPIO.BCM)
 +
 +# read data
 +MAX_ATTEMPTS = 15
 +MAX_NOT_FOUND_ATTEMPTS = 3
 +dht = DHT(pin, isDht11)
 +result = dht.read()
 +not_found_attempts = 0
 +
 +# make some attempts, because someone may not be successful
 +for x in range(0, MAX_ATTEMPTS):
 +    if result.is_valid() or not_found_attempts == MAX_NOT_FOUND_ATTEMPTS:
 +        break
 +    else:
 +        time.sleep(2)
 +        result = dht.read()
 +        if result.error_code == DHTResult.ERR_NOT_FOUND:
 +            not_found_attempts += 1
 +        else:
 +            not_found_attempts = 0
 +
 +            
 +# print result
 +if result.is_valid():
 +    print('Temp: {0:0.1f} C  Humidity: {1:0.1f} %'.format(result.temperature, result.humidity))
 +else:
 +    print('Failed to get reading. Is the sensor connected? Is the pin number correct?')
 +    
 +# clean the gpio
 +GPIO.cleanup()
 +
 +
 +</code></hidden>
 +
 +
 +Je peux lancer le script en faisant : 
 +
 +<code bash>source /home/pi/.venv/bin/activate
 +cd /home/pi
 +sudo .venv/bin/python3 ./dht.py 22 25</code>
 +(ici 22 pour DHT22, et 25 pour le GPIO25)
 +
 +
 +@TODO : 
 +  * <del>Modifier dht.py pour formater et renvoyer temp+humid en json</del>
 +  * <del>Créer https://poul.fr.nf/info_dht.php qui récupère en json les infos de dht.py</del>
 +  * <del>Modifier https://poul.fr.nf/info_proc.php pour qu'elle récupère les infos proc uniquement (plus la partie dht)</del>
 +  * <del>Modifier l'interface index.php pour :</del>
 +    * <del>Lancer un "pisto/put_info_proc_in_bdd_post.php" (tant qu'à faire ça donne un enregistrement plus récent) >>> finalement non, ça va ajouter pas mal de données en BDD pour rien (1 data par heure ça donne déjà 88k ligne en 10 ans, et si on reste sur le site ça ajoute des lignes toutes les 15s...)</del>
 +    * <del>Récupérer température/humidité par info_dht.php</del>
 +  * <del>Rapatrier les données via nextcloud-cmd</del>
 +  * Migrer sur le pi "en prod" (attention au path de .venv !)
 +  * Modifier pisto/put_info_proc_in_bdd_post.php pour pointer sur cette nouvelle page info_dht.php
 +
 +@TODO : 
 +  * Motion
 +    * Mise en place caméra
 +    * Mise en place timelapse (on move ?)
 +    * MEP IR
 +@TODO :
 +  * Récupérer les tutos de pistodocs\Perso\configs\Scripts\RPI-Poulailler
 +  * log2ram (et modifs des fichiers logs pour /tmp)
  
linux/rpi/installation.1745685458.txt.gz · Dernière modification : 2025/04/26 16:37 de tutospisto