Reviewed-on: #2
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
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)
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
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 :
git config core.hooksPath .githooks
Format attendu :
<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 :
cd ~/pont-bascule-connector
nano .env
Exemple (mode reel / port serie) :
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) :
APP_MODE=mock
APP_HOST=0.0.0.0
APP_PORT=8000
Notes importantes :
APP_MODE=serial(defaut) utilise le port serie ;APP_MODE=mocksimule les reponses pour le dev.APP_HOSTetAPP_PORTpermettent de changer l'interface d'ecoute et le port HTTP.SERIAL_OPEN_DELAY_S=2.0etSERIAL_POST_WRITE_DELAY_S=0.5reproduisent 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, adaptezSERIAL_PORT
Droits port série (dialout)
Vérifier les devices :
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 :
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)
source ./.venv/bin/activate
uvicorn app.main:app --host 0.0.0.0 --port 8000
Test local :
curl http://127.0.0.1:8000/health
Lancer l'API au démarrage (systemd)
1) Créer le service
sudo nano /etc/systemd/system/pont-bascule-api.service
Contenu (adapter les chemins et l'utilisateur) :
[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
sudo systemctl daemon-reload
sudo systemctl enable --now pont-bascule-api
sudo systemctl status pont-bascule-api --no-pager
3) Logs
journalctl -u pont-bascule-api -f
API — Endpoints
Santé
GET /health
Exemple :
curl http://127.0.0.1:8000/health
Dernière réponse (debug)
GET /last
Envoi trame "Esclave"
POST /send/esclave
curl -X POST http://127.0.0.1:8000/send/esclave
Envoi trame "DSD"
POST /send/dsd
curl -X POST http://127.0.0.1:8000/send/dsd
Envoi trame custom (hex)
POST /send/custom
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 bruteduration_ms: durée de l'opérationerror: message d'erreur si problème
Exemple (indicatif) :
{
"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 :
tailscale status
tailscale ip -4
Exemple : IP Tailscale 100.122.43.54.
2) Appeler l'API via Tailscale (simple)
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 :
sudo tailscale serve --http=80 localhost:8000
sudo tailscale serve status
Ensuite :
curl http://100.122.43.54/health
curl -X POST http://100.122.43.54/send/esclave
Dépannage rapide
API down
sudo systemctl status pont-bascule-api --no-pager
journalctl -u pont-bascule-api -n 100 --no-pager
Port série introuvable
ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null
dmesg | tail -n 50
Permission refusée
groups
# dialout doit apparaître
Pas de réponse
- vérifier le baudrate
- vérifier le port
/dev/ttyUSB0vs/dev/ttyACM0 - augmenter
SERIAL_POST_WRITE_DELAY_S(ex: 1.0) si la réponse arrive lentement
Sécurité recommandée (optionnel)
-
Exposer l'API uniquement via Tailscale :
- faire écouter uvicorn en local seulement (
--host 127.0.0.1) - utiliser
tailscale servecomme reverse proxy
- faire écouter uvicorn en local seulement (
-
Ajouter un token API si besoin (header
Authorization) -
Ajouter une route
/weightqui parse la chaîneresponse_asciiet renvoieweight+unit+ticketproprement.
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).