From a5a764dca405394f81035aace571bcd23c0016fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Delr=C3=A9?= Date: Thu, 14 May 2026 11:04:26 +0200 Subject: [PATCH] chore: untrack AUDIT.md and CLAUDE.md, keep local only Remove both files from git history and add them to .gitignore. They remain on disk for local use but will never be committed. Co-authored-by: agilicode --- .gitignore | 2 + AUDIT.md | 266 ----------------------------------------------------- CLAUDE.md | 121 ------------------------ 3 files changed, 2 insertions(+), 387 deletions(-) delete mode 100644 AUDIT.md delete mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore index 7f8ef39..56cb6f7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ __pycache__/ *.pyo .env .pytest_cache/ +AUDIT.md +CLAUDE.md diff --git a/AUDIT.md b/AUDIT.md deleted file mode 100644 index 61cc57c..0000000 --- a/AUDIT.md +++ /dev/null @@ -1,266 +0,0 @@ -# Audit - BME280 Sensor Project - -**Scope:** `bme280.py`, `sensor-api.py` | **Files:** 2 | **Findings:** 2 ❌ 3 ⚠️ 4 💡 - ---- - -## TL;DR - -Projet fonctionnel mais en Python 2 avec des credentials en clair. La priorité absolue est la migration Python 3 et la sécurisation de la config. Une fois ça fait, le code est structurellement sain et prêt pour un pipeline CI. - ---- - -## Findings - -❌ **Credentials MQTT hardcodés dans le source** - `sensor-api.py:9-14` - Mot de passe, IP du broker, username directement dans le code versionné. - **Fix:** variables d'environnement via `os.environ.get()` + fichier `.env` exclu du git. - -```python -# Avant -password = 'chi6pa9tiom3chahhohB7sienicae2aimimeefei4queol7eesuthohcai6maiph' -broker_host = '192.168.86.35' - -# Après -import os -password = os.environ.get('MQTT_PASSWORD', '') -broker_host = os.environ.get('MQTT_BROKER_HOST', 'localhost') -``` - -❌ **Python 2** - `bme280.py:208-215` - Syntaxe `print "..."` sans parenthèses, EOL depuis janvier 2020. Plus de patches de sécurité, incompatible avec les outils modernes (pytest, mypy, etc.). - **Fix:** migration vers Python 3 + remplacement de `smbus` par `smbus2`. - -```python -# Avant -print "Temperature :", temperature, "C" - -# Après -print(f"Temperature : {temperature:.2f} °C") -``` - -⚠️ **Aucune gestion d'erreur** - `sensor-api.py`, `bme280.py` - Si le capteur est absent, l'I2C plante ou le broker MQTT est injoignable, l'API retourne une 500 brute sans message utile. - **Fix:** try/except avec réponse JSON structurée et code HTTP approprié. - -```python -@app.route('/bme280') -def bme280_action(): - try: - return jsonify(bme280.sensor()) - except OSError as e: - return jsonify({'error': 'Sensor unavailable', 'detail': str(e)}), 503 -``` - -⚠️ **Flask en mode debug en production** - `sensor-api.py:43` - `debug=True` active le debugger Werkzeug interactif, exécutable à distance sur le réseau. - **Fix:** `debug=False` ou piloter via variable d'environnement `FLASK_DEBUG`. - -⚠️ **`bme280.pyc` tracké dans git** - Bytecode compilé qui ne devrait pas être versionné. Il peut diverger silencieusement de la source. - **Fix:** ajouter `.gitignore` avec `*.pyc` et `__pycache__/`. - -💡 **Pas de `requirements.txt`** - dépendances implicites non documentées - `smbus2`, `flask`, `paho-mqtt` doivent être devinées à la lecture du code. - **Fix:** `requirements.txt` minimal avec les versions fixées. - -💡 **Adresse I2C hardcodée à 0x77** - `bme280.py:28` - Le BME280 supporte aussi l'adresse 0x76 (selon câblage SDO). Rendre configurable couvre les deux variantes. - -💡 **Bus SMBus instancié au niveau module** - `bme280.py:31` - `bus = smbus.SMBus(1)` s'exécute à l'import, ce qui fait crasher tout test unitaire sur une machine sans hardware I2C. - **Fix:** instancier le bus dans les fonctions qui en ont besoin, ou l'injecter en paramètre. - -💡 **`feature/v2` non mergée + commit "try POO way" orphelin** - Code potentiellement utile qui dort dans une branche non intégrée. - ---- - -## Roadmap modernisation - -### 1. Python 3 + dépendances propres - -- Remplacer `smbus` par `smbus2` (compatible Python 3, même API) -- Réécrire `bme280.py` en Python 3 avec type hints -- Créer `requirements.txt` - -``` -smbus2==0.4.3 -flask==3.1.0 -paho-mqtt==2.1.0 -python-dotenv==1.0.1 -``` - -### 2. Configuration externalisée - -Créer `.env.example` (versionné) et `.env` (ignoré) : - -```ini -# .env.example -MQTT_BROKER_HOST=192.168.1.x -MQTT_USERNAME=homeassistant -MQTT_PASSWORD= -MQTT_CLIENT_ID=rpi-bme280 -BME280_I2C_ADDRESS=0x77 -BME280_I2C_BUS=1 -FLASK_PORT=5000 -FLASK_DEBUG=false -``` - -### 3. Gestion d'erreurs et HTTP sémantique - -| Cas | Status actuel | Status cible | -|-----|--------------|--------------| -| Capteur absent | 500 (crash) | 503 Service Unavailable | -| Lecture I2C timeout | 500 (crash) | 503 + retry header | -| MQTT broker injoignable | 500 (crash) | 502 Bad Gateway | -| Succès publish | 200 `{}` | 200 `{"published": true, "topics": [...]}` | - -### 4. Qualité de code - -- Type hints sur toutes les fonctions publiques -- Dataclass ou TypedDict pour la structure sensor -- `bus` instancié dans les fonctions (testabilité) -- `snake_case` cohérent (renommer `sensor-api.py` en `sensor_api.py`) - -### 5. Tests unitaires - -Le projet est très bien adapté aux tests car le hardware est isolable par mock : - -```python -# tests/test_bme280.py -from unittest.mock import patch, MagicMock - -def test_sensor_returns_expected_structure(): - mock_bus = MagicMock() - mock_bus.read_i2c_block_data.return_value = [0] * 24 - with patch('bme280.smbus2.SMBus', return_value=mock_bus): - result = bme280.sensor() - assert 'data' in result - assert 'temperature' in result['data'] - -# tests/test_api.py -def test_bme280_endpoint(client, mock_sensor): - resp = client.get('/bme280') - assert resp.status_code == 200 - assert resp.json['name'] == 'bme280' - -def test_sensor_unavailable_returns_503(client): - with patch('bme280.sensor', side_effect=OSError('I2C error')): - resp = client.get('/bme280') - assert resp.status_code == 503 -``` - -### 6. GitHub Actions CI - -Ce que la pipeline peut valider sans hardware réel : - -| Job | Outil | Ce que ça couvre | -|-----|-------|-----------------| -| Lint | `flake8` | Style, erreurs évidentes | -| Types | `mypy` | Cohérence des type hints | -| Tests | `pytest` + mocks | Logique métier et routes Flask | -| Sécurité | `pip-audit` | CVE dans les dépendances | - -```yaml -# .github/workflows/ci.yml -name: CI - -on: [push, pull_request] - -jobs: - quality: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - run: pip install -r requirements.txt -r requirements-dev.txt - - run: flake8 bme280.py sensor_api.py - - run: mypy bme280.py sensor_api.py - - run: pytest tests/ -v --tb=short - - run: pip-audit -``` - -### 7. Documentation - -- README complet avec badges CI, exemples curl, schéma d'architecture -- Exemples d'intégration Home Assistant (MQTT discovery) -- Docstrings sur les fonctions publiques -- Schéma de câblage I2C Raspberry Pi / BME280 - ---- - -## Exemples d'utilisation cibles - -### CLI - -```bash -# Lecture directe -python bme280.py -# Temperature : 21.55 °C | Pressure : 1005.16 hPa | Humidity : 44.57 %RH - -# Avec adresse I2C alternative -BME280_I2C_ADDRESS=0x76 python bme280.py -``` - -### API HTTP - -```bash -# Démarrer l'API -python sensor_api.py - -# Lire les données capteur -curl http://rpi.local:5000/bme280 | python -m json.tool - -# Publier vers MQTT -curl -X POST http://rpi.local:5000/bme280/publish -# {"published": true, "topics": ["sensor/bme280_temperature", ...]} - -# Healthcheck -curl http://rpi.local:5000/health -# {"status": "ok", "sensor": "connected"} -``` - -### Intégration Home Assistant (MQTT Discovery) - -```yaml -# configuration.yaml -mqtt: - sensor: - - name: "BME280 Temperature" - state_topic: "sensor/bme280_temperature" - unit_of_measurement: "°C" - device_class: temperature - - name: "BME280 Humidity" - state_topic: "sensor/bme280_humidity" - unit_of_measurement: "%" - device_class: humidity - - name: "BME280 Pressure" - state_topic: "sensor/bme280_pressure" - unit_of_measurement: "hPa" - device_class: atmospheric_pressure -``` - -### Cron (après migration) - -```bash -# Publier toutes les minutes -* * * * * curl -s -X POST http://localhost:5000/bme280/publish >> /var/log/bme280.log 2>&1 -``` - ---- - -## Résumé - -| Priorité | Action | Effort | -|----------|--------|--------| -| ❌ Immédiat | Retirer les credentials du code | 30 min | -| ❌ Court terme | Migration Python 3 | 2h | -| ⚠️ Court terme | Gestion d'erreurs + `.gitignore` | 1h | -| 💡 Moyen terme | Tests unitaires + CI GitHub Actions | 3h | -| 💡 Moyen terme | Docker + `.env.example` | 1h | -| 💡 Long terme | README complet + exemples | 2h | - -**Verdict:** Le coeur algorithmique (calibration BME280) est correct et bien isolable. La dette principale est Python 2 + sécurité. Une fois ces deux points traités, le projet peut servir de base solide avec pipeline CI complète. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 91e525f..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,121 +0,0 @@ -# CLAUDE.md - BME280 Sensor Project - -## Contexte du projet - -Driver Python pour le capteur environnemental Bosch BME280 (température, pression, humidité) sur Raspberry Pi, exposé via une API HTTP Flask et une publication MQTT vers Home Assistant. - -**Matériel cible:** Raspberry Pi (Rev 2+, bus I2C n°1) + capteur Waveshare BME280 (SKU 15231) -**Adresse I2C par défaut:** 0x77 (alternatif 0x76 selon câblage SDO) - ---- - -## Architecture - -``` -bme280.py Driver bas niveau I2C + calculs de calibration (datasheet Bosch) -sensor_api.py API Flask HTTP + publication MQTT vers Home Assistant -``` - -Le driver lit les registres EEPROM du BME280, applique les algorithmes de compensation du datasheet officiel (page 22+), et retourne température/pression/humidité calibrées. - ---- - -## Etat actuel du code - -**Attention:** le code est en Python 2. Voir `AUDIT.md` pour la roadmap de modernisation complète. - -Dépendances implicites (pas de requirements.txt) : -- `smbus` (Python 2) - à remplacer par `smbus2` lors de la migration Python 3 -- `flask` -- `paho-mqtt` - ---- - -## Contraintes hardware - -Le code `bme280.py` ne peut pas tourner sans un vrai bus I2C. Sur une machine de dev (CI, laptop), **toujours mocker `smbus`** : - -```python -from unittest.mock import patch, MagicMock - -mock_bus = MagicMock() -mock_bus.read_i2c_block_data.return_value = [0] * 24 -with patch('bme280.smbus.SMBus', return_value=mock_bus): - # test ici -``` - -Le `bus = smbus.SMBus(1)` est instancié au niveau module dans l'état actuel, ce qui fait crasher l'import sans hardware. Lors de la refonte, il faut déplacer cette instanciation dans les fonctions. - ---- - -## Algorithmes critiques - -Les fonctions de compensation dans `readBME280All()` sont tirées directement du datasheet Bosch (Appendix). **Ne pas modifier sans vérifier contre la spec officielle.** Les constantes magiques (32768, 524288, 67108864...) sont des puissances de 2 issues du datasheet, pas des valeurs arbitraires. - ---- - -## Configuration sensible - -`sensor-api.py` contient actuellement des credentials MQTT hardcodés. Ne pas les modifier directement dans le source, la cible est de les externaliser en variables d'environnement. Voir `AUDIT.md` pour le plan. - -Variables d'environnement cibles (après migration) : - -| Variable | Défaut | Description | -|----------|--------|-------------| -| `MQTT_BROKER_HOST` | `localhost` | IP ou hostname du broker | -| `MQTT_USERNAME` | - | Username MQTT | -| `MQTT_PASSWORD` | - | Password MQTT | -| `MQTT_CLIENT_ID` | `rpi-bme280` | Client ID MQTT | -| `BME280_I2C_ADDRESS` | `0x77` | Adresse I2C du capteur | -| `BME280_I2C_BUS` | `1` | Numéro de bus I2C | -| `FLASK_PORT` | `5000` | Port HTTP | - ---- - -## Lancer le projet - -```bash -# CLI directe (sur le Pi uniquement) -python bme280.py - -# API HTTP (sur le Pi uniquement) -python sensor-api.py -# Écoute sur 0.0.0.0:5000 -``` - ---- - -## Branches - -| Branche | Etat | -|---------|------| -| `develop` | Branche principale active | -| `master` | Remote uniquement | -| `feature/v2` | Remote non mergée - tentative POO abandonnée | - ---- - -## Roadmap - -Le détail complet est dans `AUDIT.md`. Les grandes étapes : - -1. Externaliser les credentials (sécurité, immédiat) -2. Migration Python 3 + `smbus2` -3. `requirements.txt` + `.gitignore` -4. Gestion d'erreurs dans l'API -5. Tests unitaires avec mocks hardware -6. Pipeline GitHub Actions CI - ---- - -## Tests - -Pas de tests actuellement. La cible est `pytest` avec mocks smbus et Flask test client. Voir la section "Tests unitaires" dans `AUDIT.md` pour les exemples. - -Structure cible : - -``` -tests/ -├── test_bme280.py # Calibration, parsing registres -└── test_api.py # Routes Flask, gestion d'erreurs -```