381 lines
7.4 KiB
Markdown
381 lines
7.4 KiB
Markdown
# Pont Bascule Connector — FastAPI + Serial + (optionnel) Tailscale
|
|
|
|
API HTTP (FastAPI) qui pilote un pont bascule connecté en USB (port série) sur Raspberry Pi ou Linux.
|
|
|
|
**Objectif :** permettre à une application/serveur distant d'interroger le pont bascule via réseau, avec une contrainte stricte : **1 requête série à la fois**.
|
|
|
|
---
|
|
|
|
## Fonctionnement global
|
|
|
|
```
|
|
Client (PC / serveur / app) --HTTP--> Machine (FastAPI)
|
|
|
|
|
| 1 appel à la fois (lock)
|
|
v
|
|
Port série (/dev/ttyUSB0)
|
|
|
|
|
v
|
|
Pont bascule
|
|
```
|
|
|
|
**Accès distant (optionnel) :**
|
|
- via IP Tailscale `100.x.x.x` (VPN mesh)
|
|
- ou autre VPN / reverse-proxy selon votre infra
|
|
|
|
---
|
|
|
|
## Prérequis
|
|
|
|
### Matériel
|
|
- Pont bascule branché en USB (ou via adaptateur USB↔RS232/RS485 selon le matériel)
|
|
|
|
### Système
|
|
- Raspberry Pi OS / Debian / Ubuntu (autres Linux OK)
|
|
- Python 3.9+ recommandé
|
|
- Accès SSH
|
|
- (optionnel) Tailscale installé et connecté
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
### 1) Récupérer le projet
|
|
|
|
```bash
|
|
cd ~
|
|
git clone gitea@gitea.malio.fr:MALIO-DEV/pont-bascule-connector.git
|
|
cd pont-bascule-connector
|
|
```
|
|
|
|
### 2) Installer les dépendances système (Debian/Ubuntu/Raspberry Pi OS)
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt install -y python3 python3-venv python3-pip git
|
|
```
|
|
|
|
Si vous êtes sur un autre OS, installez Python 3 + pip + venv via votre gestionnaire de paquets.
|
|
|
|
### 3) Installer les dépendances Python
|
|
|
|
```bash
|
|
python3 -m venv ./.venv
|
|
source ./.venv/bin/activate
|
|
pip install --upgrade pip
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
---
|
|
|
|
## Hook git (commit-msg)
|
|
|
|
Le repo contient un hook pour valider le format des messages de commit.
|
|
|
|
Activation :
|
|
|
|
```bash
|
|
git config core.hooksPath .githooks
|
|
```
|
|
|
|
Format attendu :
|
|
|
|
```text
|
|
<type>(<scope optionnel>) : <message>
|
|
```
|
|
|
|
Types autorisés : `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`.
|
|
|
|
---
|
|
|
|
## Configuration série (.env)
|
|
|
|
Le fichier `.env` est chargé automatiquement au démarrage (via `python-dotenv`).
|
|
|
|
Créer un fichier `.env` à la racine du projet :
|
|
|
|
```bash
|
|
cd ~/pont-bascule-connector
|
|
nano .env
|
|
```
|
|
|
|
Exemple (mode reel / port serie) :
|
|
|
|
```env
|
|
APP_MODE=serial
|
|
APP_HOST=0.0.0.0
|
|
APP_PORT=8000
|
|
SERIAL_PORT=/dev/ttyUSB0
|
|
SERIAL_BAUDRATE=9600
|
|
SERIAL_TIMEOUT_S=1.0
|
|
SERIAL_OPEN_DELAY_S=2.0
|
|
SERIAL_POST_WRITE_DELAY_S=0.5
|
|
```
|
|
|
|
Exemple (mode mock pour dev, sans port serie) :
|
|
|
|
```env
|
|
APP_MODE=mock
|
|
APP_HOST=0.0.0.0
|
|
APP_PORT=8000
|
|
```
|
|
|
|
**Notes importantes :**
|
|
|
|
- `APP_MODE=serial` (defaut) utilise le port serie ; `APP_MODE=mock` simule les reponses pour le dev.
|
|
- `APP_HOST` et `APP_PORT` permettent de changer l'interface d'ecoute et le port HTTP.
|
|
- `SERIAL_OPEN_DELAY_S=2.0` et `SERIAL_POST_WRITE_DELAY_S=0.5` reproduisent le comportement du script Tkinter historique :
|
|
- attente 2s après ouverture du port
|
|
- envoi trame
|
|
- attente 0.5s
|
|
- lecture une seule fois de `in_waiting`
|
|
- Si votre port est `/dev/ttyACM0`, adaptez `SERIAL_PORT`
|
|
|
|
---
|
|
|
|
## Droits port série (dialout)
|
|
|
|
Vérifier les devices :
|
|
|
|
```bash
|
|
ls /dev/ttyUSB* 2>/dev/null || true
|
|
ls /dev/ttyACM* 2>/dev/null || true
|
|
dmesg | tail -n 30
|
|
```
|
|
|
|
Ajouter l'utilisateur courant au groupe `dialout` :
|
|
|
|
```bash
|
|
sudo usermod -aG dialout "$USER"
|
|
newgrp dialout
|
|
```
|
|
|
|
Si besoin, reconnectez-vous (ou redémarrez) pour que les droits prennent effet.
|
|
|
|
---
|
|
|
|
## Lancer l'API (mode manuel)
|
|
|
|
```bash
|
|
source ./.venv/bin/activate
|
|
uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
```
|
|
|
|
Test local :
|
|
|
|
```bash
|
|
curl http://127.0.0.1:8000/health
|
|
```
|
|
|
|
---
|
|
|
|
## Lancer l'API au démarrage (systemd)
|
|
|
|
### 1) Créer le service
|
|
|
|
```bash
|
|
sudo nano /etc/systemd/system/pont-bascule-api.service
|
|
```
|
|
|
|
Contenu (adapter les chemins et l'utilisateur) :
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=Pont bascule API (FastAPI)
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
User=<votre_user>
|
|
WorkingDirectory=/home/<votre_user>/pont-bascule-connector
|
|
EnvironmentFile=/home/<votre_user>/pont-bascule-connector/.env
|
|
ExecStart=/home/<votre_user>/pont-bascule-connector/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
Restart=always
|
|
RestartSec=2
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
### 2) Activer et démarrer
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now pont-bascule-api
|
|
sudo systemctl status pont-bascule-api --no-pager
|
|
```
|
|
|
|
### 3) Logs
|
|
|
|
```bash
|
|
journalctl -u pont-bascule-api -f
|
|
```
|
|
|
|
---
|
|
|
|
## API — Endpoints
|
|
|
|
### Santé
|
|
|
|
**GET** `/health`
|
|
|
|
Exemple :
|
|
|
|
```bash
|
|
curl http://127.0.0.1:8000/health
|
|
```
|
|
|
|
### Dernière réponse (debug)
|
|
|
|
**GET** `/last`
|
|
|
|
### Envoi trame "Esclave"
|
|
|
|
**POST** `/send/esclave`
|
|
|
|
```bash
|
|
curl -X POST http://127.0.0.1:8000/send/esclave
|
|
```
|
|
|
|
### Envoi trame "DSD"
|
|
|
|
**POST** `/send/dsd`
|
|
|
|
```bash
|
|
curl -X POST http://127.0.0.1:8000/send/dsd
|
|
```
|
|
|
|
### Envoi trame custom (hex)
|
|
|
|
**POST** `/send/custom`
|
|
|
|
```bash
|
|
curl -X POST http://127.0.0.1:8000/send/custom \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"hex":"01 0D 0A"}'
|
|
```
|
|
|
|
### Format de réponse
|
|
|
|
La réponse renvoie :
|
|
|
|
- `response_ascii` : texte décodé ASCII (souvent le poids + infos)
|
|
- `response_hex` : trame brute
|
|
- `duration_ms` : durée de l'opération
|
|
- `error` : message d'erreur si problème
|
|
|
|
Exemple (indicatif) :
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"mode": "serial",
|
|
"port": "/dev/ttyUSB0",
|
|
"baudrate": 9600,
|
|
"request_hex": "01 0D 0A",
|
|
"response_hex": "30 30 31 32 2E 33 34 20 6B 67",
|
|
"response_ascii": "0012.34 kg",
|
|
"duration_ms": 2600,
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Contrainte "1 appel à la fois" (important)
|
|
|
|
Le port série ne doit pas être utilisé en concurrence.
|
|
|
|
Si une requête est déjà en cours, l'API renvoie :
|
|
- **HTTP 409**
|
|
- message **BUSY**
|
|
|
|
---
|
|
|
|
## Accès à distance via Tailscale (optionnel)
|
|
|
|
### 1) Vérifier Tailscale
|
|
|
|
Sur la machine :
|
|
|
|
```bash
|
|
tailscale status
|
|
tailscale ip -4
|
|
```
|
|
|
|
Exemple : IP Tailscale `100.122.43.54`.
|
|
|
|
### 2) Appeler l'API via Tailscale (simple)
|
|
|
|
```bash
|
|
curl http://100.122.43.54:8000/health
|
|
curl -X POST http://100.122.43.54:8000/send/esclave
|
|
```
|
|
|
|
### 3) Option recommandée : exposer sans port avec `tailscale serve`
|
|
|
|
Sur la machine :
|
|
|
|
```bash
|
|
sudo tailscale serve --http=80 localhost:8000
|
|
sudo tailscale serve status
|
|
```
|
|
|
|
Ensuite :
|
|
|
|
```bash
|
|
curl http://100.122.43.54/health
|
|
curl -X POST http://100.122.43.54/send/esclave
|
|
```
|
|
|
|
---
|
|
|
|
## Dépannage rapide
|
|
|
|
### API down
|
|
|
|
```bash
|
|
sudo systemctl status pont-bascule-api --no-pager
|
|
journalctl -u pont-bascule-api -n 100 --no-pager
|
|
```
|
|
|
|
### Port série introuvable
|
|
|
|
```bash
|
|
ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null
|
|
dmesg | tail -n 50
|
|
```
|
|
|
|
### Permission refusée
|
|
|
|
```bash
|
|
groups
|
|
# dialout doit apparaître
|
|
```
|
|
|
|
### Pas de réponse
|
|
|
|
- vérifier le baudrate
|
|
- vérifier le port `/dev/ttyUSB0` vs `/dev/ttyACM0`
|
|
- augmenter `SERIAL_POST_WRITE_DELAY_S` (ex: 1.0) si la réponse arrive lentement
|
|
|
|
---
|
|
|
|
## Sécurité recommandée (optionnel)
|
|
|
|
1. **Exposer l'API uniquement via Tailscale :**
|
|
- faire écouter uvicorn en local seulement (`--host 127.0.0.1`)
|
|
- utiliser `tailscale serve` comme reverse proxy
|
|
|
|
2. **Ajouter un token API** si besoin (header `Authorization`)
|
|
|
|
3. **Ajouter une route `/weight`** qui parse la chaîne `response_ascii` et renvoie `weight` + `unit` + `ticket` proprement.
|
|
|
|
---
|
|
|
|
## Recommandations utiles
|
|
|
|
### Port série stable (udev)
|
|
|
|
Si votre port passe parfois de `/dev/ttyUSB0` à `/dev/ttyUSB1`, on peut créer une règle udev pour avoir un nom fixe (ex: `/dev/pontbascule`).
|