Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
| asso:si:si_garage [2026/08/11 00:10] – grapsus | asso:si:si_garage [2026/10/12 22:04] (Version actuelle) – La route locale est aussi appelée par le bouton garage du Pi de la porte (gatepi) nrineau | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| - | ===== Système d' | + | ===== Système d' |
| - | Le système d' | + | Le boîtier rose fixé près du garage |
| - | Pré-requis: | + | * **Framateam (Mattermost)** |
| - | < | + | * **Badge RFID** : un badge de la liste ouvre le **garage** uniquement. |
| - | apt install python3-flask python3-serial | + | |
| - | adduser lov dialout | + | |
| - | </ | + | |
| - | Code du serveur dans /home/lov/garage: | + | {{ : |
| - | < | + | |
| - | from flask import Flask | + | |
| - | app = Flask(__name__) | + | |
| - | import serial | + | |
| - | ARDUINO = '/dev/serial/by-id/usb-Arduino__www.arduino.cc__Arduino_Uno_64938323131351213190-if00' | + | //Schéma réalisé avec [[https:// |
| - | @app.route('/ | + | ==== Électronique ==== |
| - | def open(): | + | |
| - | try: | + | |
| - | with serial.Serial(port=ARDUINO, baudrate=9600) as f: | + | |
| - | banner | + | |
| - | if ' | + | |
| - | return " | + | |
| - | f.write(b' | + | |
| - | f.flush() | + | |
| - | resp = f.readline().decode(' | + | |
| - | return " | + | |
| - | except serial.serialutil.SerialException as e: | + | |
| - | return str(e) | + | |
| - | if __name__ == ' | + | {{ :asso: |
| - | app.run(host=' | + | |
| - | </ | + | |
| - | < | + | Schéma Fritzing modifiable : {{: |
| + | |||
| + | {{ : | ||
| + | {{ : | ||
| + | {{ : | ||
| + | |||
| + | ^ Broche Arduino ^ Fonction ^ Fonctionnement ^ | ||
| + | | D9 | Bouton de la télécommande du garage | Mise à la masse pendant 800 ms = appui (ouvre **ou** ferme) | | ||
| + | | D10 | Télécommande de la serrure : **ouvrir** | Impulsion 5 V de 2,5 s | | ||
| + | | D11 | Télécommande de la serrure : **fermer** | Impulsion 5 V de 2,5 s | | ||
| + | | USB | Liaison avec l'Atom | Série 9600 bauds, puce CH340 | | ||
| + | |||
| + | La télécommande du garage (PCB vert HXQ920BT-4) n'a plus de pile : elle est alimentée par l' | ||
| + | |||
| + | Anciennement, | ||
| + | |||
| + | ==== Firmware Arduino (LOV garage opener v3) ==== | ||
| + | |||
| + | Protocole : un caractère sur le port série (9600 bauds). '' | ||
| + | |||
| + | < | ||
| #include < | #include < | ||
| Ligne 45: | Ligne 44: | ||
| pinMode(11, OUTPUT); | pinMode(11, OUTPUT); | ||
| digitalWrite(11, | digitalWrite(11, | ||
| - | |||
| Serial.begin(9600); | Serial.begin(9600); | ||
| Ligne 55: | Ligne 53: | ||
| servo.detach(); | servo.detach(); | ||
| pinMode(9, INPUT); | pinMode(9, INPUT); | ||
| - | digitalWrite(9, | + | digitalWrite(9, |
| } | } | ||
| Ligne 62: | Ligne 60: | ||
| c = Serial.read(); | c = Serial.read(); | ||
| if (c == ' | if (c == ' | ||
| - | //Code for activating the servo of that simulates a click on the real life remote of the garagedoor | ||
| Serial.println(" | Serial.println(" | ||
| / | / | ||
| Ligne 72: | Ligne 69: | ||
| pinMode(9, OUTPUT); | pinMode(9, OUTPUT); | ||
| digitalWrite(9, | digitalWrite(9, | ||
| - | delay(1000); | + | delay(800); |
| pinMode(9, INPUT); | pinMode(9, INPUT); | ||
| + | digitalWrite(9, | ||
| Serial.println(" | Serial.println(" | ||
| } else if (c == ' | } else if (c == ' | ||
| Ligne 93: | Ligne 91: | ||
| </ | </ | ||
| - | Pour lancer | + | Vérifié le 10/10/2026 : ce code correspond |
| + | |||
| + | ==== Serveur (Atom) ==== | ||
| + | |||
| + | Pré-requis | ||
| < | < | ||
| - | sudo -u lov -g lov /usr/bin/python3 | + | apt install python3-flask python3-serial |
| + | adduser lov dialout | ||
| </ | </ | ||
| + | |||
| + | Fichiers dans ''/ | ||
| + | |||
| + | ^ Fichier ^ Rôle ^ | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | **nginx** écoute sur le port **4280** et ne transmet au serveur Flask que les URL secrètes (voir ''/ | ||
| + | |||
| + | ^ Route ^ Déclenchée par ^ Action ^ Contrôle ^ | ||
| + | | ouverture locale (GET) | '' | ||
| + | | garage (POST) | commande slash Framateam | garage | canal garage ou canal porte | | ||
| + | | entrer (POST) | commande slash Framateam | ouvre la porte arrière + message « X a ouvert le local » | canal porte | | ||
| + | | sortir (POST) | commande slash Framateam | ferme la porte arrière + message « X a fermé le local » | canal porte | | ||
| + | |||
| + | ==== Code du serveur (server.py) ==== | ||
| + | |||
| + | Version en service sur l'atom (''/ | ||
| + | |||
| + | <code python> | ||
| + | from flask import Flask, request, jsonify | ||
| + | app = Flask(__name__) | ||
| + | import serial | ||
| + | |||
| + | ARDUINO = '/ | ||
| + | GARAGE_CHANNEL = '< | ||
| + | PORTE_CHANNEL = '< | ||
| + | |||
| + | def send_command(c): | ||
| + | try: | ||
| + | with serial.Serial(port=ARDUINO, | ||
| + | banner = f.readline().decode(' | ||
| + | if ' | ||
| + | return " | ||
| + | f.write(c) | ||
| + | f.flush() | ||
| + | resp = f.readline().decode(' | ||
| + | return " | ||
| + | except serial.serialutil.SerialException as e: | ||
| + | return str(e) | ||
| + | |||
| + | # uncondtionnally open the garage (for local usage) | ||
| + | @app.route('/< | ||
| + | def local_open(): | ||
| + | return send_command(b' | ||
| + | |||
| + | @app.route('/< | ||
| + | def open(): | ||
| + | user_name = request.form.get(' | ||
| + | channel_id = request.form.get(' | ||
| + | if channel_id != GARAGE_CHANNEL and channel_id != PORTE_CHANNEL: | ||
| + | return "this is not the command you are looking for" | ||
| + | return send_command(b' | ||
| + | |||
| + | @app.route('/< | ||
| + | def enter(): | ||
| + | user_name = request.form.get(' | ||
| + | channel_id = request.form.get(' | ||
| + | if channel_id != PORTE_CHANNEL: | ||
| + | return "this is not the command you are looking for" | ||
| + | r = send_command(b' | ||
| + | return jsonify({ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }] | ||
| + | }) | ||
| + | |||
| + | @app.route('/< | ||
| + | def leave(): | ||
| + | user_name = request.form.get(' | ||
| + | channel_id = request.form.get(' | ||
| + | if channel_id != PORTE_CHANNEL: | ||
| + | return "this is not the command you are looking for" | ||
| + | r = send_command(b' | ||
| + | return jsonify({ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }] | ||
| + | }) | ||
| + | |||
| + | if __name__ == ' | ||
| + | app.run(host=' | ||
| + | </ | ||
| + | |||
| + | Fonctionnement : | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * Le serveur n' | ||
| + | |||
| + | ==== Code du lecteur de badges (gate-service.sh) ==== | ||
| + | |||
| + | <code bash> | ||
| + | #!/bin/bash | ||
| + | |||
| + | cd $(dirname " | ||
| + | LOG=./ | ||
| + | |||
| + | (while true ; do python3 rfid.py ; sleep 1 ; done) & | ||
| + | |||
| + | validate_id() { | ||
| + | awk "/^$1 / { print \$2 }" ./perm.list | ||
| + | } | ||
| + | |||
| + | while true; do | ||
| + | inotifywait -qq -e modify " | ||
| + | date | ||
| + | l=$(tail -n 1 " | ||
| + | if ! egrep -q ' | ||
| + | echo " | ||
| + | continue | ||
| + | fi | ||
| + | c=$(cut -d ' ' -f 2 <<< | ||
| + | name=$(validate_id " | ||
| + | if [ -z " | ||
| + | echo " | ||
| + | continue | ||
| + | fi | ||
| + | echo " | ||
| + | curl http:// | ||
| + | done | ||
| + | </ | ||
| + | |||
| + | Fonctionnement : | ||
| + | * lance '' | ||
| + | * '' | ||
| + | * à chaque nouvelle ligne de '' | ||
| + | * si le badge est autorisé, il appelle la route locale du serveur (''< | ||
| + | |||
| + | Lancement au démarrage, dans ''/ | ||
| + | < | ||
| + | tmux new -s garage -d 'sudo -u lov -g lov / | ||
| + | tmux new -s rfid -d / | ||
| + | </ | ||
| + | |||
| + | Pour voir ce qui se passe : '' | ||
| + | |||
| + | ==== Ajouter un badge ==== | ||
| + | |||
| + | - Passer le badge sur le lecteur. | ||
| + | - Sur l'Atom : '' | ||
| + | - Ajouter la ligne ''< | ||
| + | |||
| + | ==== Dépannage ==== | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * Le badge ne fait rien : lecteur débranché ('' | ||
| + | * L' | ||
| + | |||
| + | Documentation technique détaillée (rétro-ingénierie, | ||
| + | |||