- BMS LC30 – Exemples Python complets
- 1. Pré-requis
- 2. Client API minimal
- 3. Lire les données principales du BMS
- 4. Diagnostic I²C
- 5. Lire et modifier la configuration avancée
- 6. Calibration tension et courant
- 7. Lire directement un registre
- 8. Écrire un registre
- 9. Utiliser les profils de registres
- 10. Informations device et cellules
- 11. Lecture des statuts et flags
- 12. Commandes MAC
- 13. Data Flash
- 14. Gestion sécurité
- 15. Exemple complet : outil console simple
- 16. Bonnes pratiques
BMS LC30 – Exemples Python complets #
Cette page regroupe des exemples Python prêts à l’emploi pour interagir avec l’API du
BMS LC30. Les exemples ci-dessous utilisent la bibliothèque requests
et s’appuient sur les routes réellement exposées par le plugin Python fourni.
1. Pré-requis #
Installer la dépendance Python nécessaire :
pip install requests
Dans les exemples suivants, l’API est supposée accessible à l’adresse :
http://127.0.0.1:5000
2. Client API minimal #
Le code ci-dessous propose un mini client Python réutilisable pour appeler les routes de l’API.
import requests
class BmsApiClient:
def __init__(self, base_url="http://127.0.0.1:5000", timeout=5):
self.base_url = base_url.rstrip("/")
self.timeout = timeout
def get(self, path, **kwargs):
response = requests.get(
f"{self.base_url}{path}",
timeout=self.timeout,
**kwargs
)
response.raise_for_status()
return response.json()
def post(self, path, payload=None, **kwargs):
response = requests.post(
f"{self.base_url}{path}",
json=payload or {},
timeout=self.timeout,
**kwargs
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
api = BmsApiClient()
print(api.get("/api/bms"))
3. Lire les données principales du BMS #
La route /api/bms fournit les données consolidées : tension, courant, SOC, alarmes,
état de charge et état de connexion.
from pprint import pprint
from time import sleep
import requests
BASE_URL = "http://127.0.0.1:5000"
def read_bms():
r = requests.get(f"{BASE_URL}/api/bms", timeout=5)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
data = read_bms()
pprint(data)
Version supervision continue #
import time
import requests
BASE_URL = "http://127.0.0.1:5000"
def read_bms():
r = requests.get(f"{BASE_URL}/api/bms", timeout=5)
r.raise_for_status()
return r.json()
while True:
try:
data = read_bms()
print(
f"connected={data.get('connected')} | "
f"soc={data.get('soc')}% | "
f"voltage={data.get('voltage')}V | "
f"current={data.get('current')}A | "
f"temp={data.get('temperature')}°C | "
f"alarms={data.get('alarms', [])}"
)
except Exception as exc:
print("Erreur lecture BMS :", exc)
time.sleep(2)
4. Diagnostic I²C #
La route /api/bms/diag permet de diagnostiquer le bus : bus disponibles, adresses présentes,
adresse cible et lecture de plusieurs registres de base.
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
def run_diag():
r = requests.get(f"{BASE_URL}/api/bms/diag", timeout=10)
r.raise_for_status()
return r.json()
if __name__ == "__main__":
diag = run_diag()
print(json.dumps(diag, indent=2, ensure_ascii=False))
Exemple de vérification simple #
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/diag", timeout=10)
r.raise_for_status()
diag = r.json()
if diag.get("connected"):
print("BMS détecté sur", diag.get("target_addr"), "bus", diag.get("target_bus"))
else:
print("BMS non détecté")
print(diag)
5. Lire et modifier la configuration avancée #
Le plugin expose une route de lecture et d’écriture de la configuration avancée, incluant le mode avancé, la source de SOC et les gains / offsets de calibration.
Lecture de configuration #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/advanced-config", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Mise à jour de configuration #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"advanced_mode": True,
"soc_source": "bms",
"full_cell_voltage": 4.2,
"empty_cell_voltage": 3.2,
"voltage_gain": 1.0,
"voltage_offset": 0.0,
"current_gain": 1.0,
"current_offset": 0.0
}
r = requests.post(f"{BASE_URL}/api/bms/advanced-config", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
6. Calibration tension et courant #
Le plugin propose des routes dédiées à la calibration tension et courant, ainsi qu’une remise à zéro des coefficients.
Calibration tension #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"reference_voltage": 15.92
}
r = requests.post(f"{BASE_URL}/api/bms/calibration/voltage", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
Calibration courant #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"reference_current": -1.48
}
r = requests.post(f"{BASE_URL}/api/bms/calibration/current", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
Reset calibration #
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.post(f"{BASE_URL}/api/bms/calibration/reset", json={}, timeout=5)
r.raise_for_status()
print(r.json())
7. Lire directement un registre #
La route /api/bms/register/read permet de lire un registre en mode
word, byte ou block. Le plugin gère aussi les valeurs signées.
Lecture de la tension pack #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"register": "0x09",
"mode": "word",
"signed": False
}
r = requests.post(f"{BASE_URL}/api/bms/register/read", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
Lecture du courant signé #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"register": "0x0A",
"mode": "word",
"signed": True
}
r = requests.post(f"{BASE_URL}/api/bms/register/read", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
Lecture d’un bloc fabricant #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"register": "0x20",
"mode": "block",
"length": 20
}
r = requests.post(f"{BASE_URL}/api/bms/register/read", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
8. Écrire un registre #
L’écriture d’un registre requiert le mode avancé et une confirmation explicite. Certains registres
restent protégés sans force_unsafe=true.
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"register": "0x17",
"mode": "word",
"value": 12,
"confirm_write": True
}
r = requests.post(f"{BASE_URL}/api/bms/register/write", json=payload, timeout=5)
print(r.status_code)
print(r.json())
9. Utiliser les profils de registres #
Le plugin contient des profils par défaut comme sbs_monitoring et
manufacturer_strings, ainsi que la possibilité de définir des profils personnalisés.
Lister les profils #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/register/profiles", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Appliquer un profil de lecture #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"profile": "sbs_monitoring",
"write_mode": False
}
r = requests.post(f"{BASE_URL}/api/bms/register/profile/apply", json=payload, timeout=10)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Créer un profil personnalisé #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"name": "pack_basic",
"label": "Pack basic",
"description": "Lecture tension, courant et SOC",
"entries": [
{"register": "0x09", "mode": "word", "signed": False, "label": "Voltage"},
{"register": "0x0A", "mode": "word", "signed": True, "label": "Current"},
{"register": "0x0D", "mode": "word", "signed": False, "label": "RelativeSOC"}
]
}
r = requests.post(f"{BASE_URL}/api/bms/register/profiles", json=payload, timeout=5)
r.raise_for_status()
print(r.json())
10. Informations device et cellules #
Les routes studio permettent de récupérer des informations plus avancées, notamment les infos device, les registres SBS complets et les tensions cellules.
Infos device #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/info", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Lecture des cellules #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/cells", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Lecture SBS complète #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/sbs", timeout=10)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
11. Lecture des statuts et flags #
La route /api/bms/studio/status permet de récupérer les différents groupes de flags :
safety, PF, operation, charging et gauging.
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/status", timeout=10)
r.raise_for_status()
status = r.json()
print(json.dumps(status, indent=2, ensure_ascii=False))
12. Commandes MAC #
Le plugin permet de lister les commandes MAC disponibles et d’en envoyer une. Certaines commandes sont marquées dangereuses et nécessitent une confirmation.
Lister les commandes MAC #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/mac_commands", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Envoyer une commande MAC #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"command": "0x0001",
"confirm": False
}
r = requests.post(f"{BASE_URL}/api/bms/studio/mac", json=payload, timeout=5)
print(r.status_code)
print(r.json())
13. Data Flash #
Le plugin expose la recherche, la lecture et l’écriture de paramètres Data Flash, ainsi que la lecture brute d’un bloc mémoire.
Lister les classes Data Flash #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/df_classes", timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Rechercher un paramètre Data Flash #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
query = "0x45CC"
r = requests.get(f"{BASE_URL}/api/bms/studio/df_search", params={"q": query}, timeout=5)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Lire une classe Data Flash #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"class": "gas_gauging"
}
r = requests.post(f"{BASE_URL}/api/bms/studio/df_read", json=payload, timeout=15)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Lire un bloc brut Data Flash #
import json
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"address": "0x4681"
}
r = requests.post(f"{BASE_URL}/api/bms/studio/df_raw", json=payload, timeout=10)
r.raise_for_status()
print(json.dumps(r.json(), indent=2, ensure_ascii=False))
Écrire un paramètre Data Flash #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"address": "0x45CC",
"value": 4200,
"size": 2,
"signed": False,
"confirm": True
}
r = requests.post(f"{BASE_URL}/api/bms/studio/df_write", json=payload, timeout=10)
print(r.status_code)
print(r.json())
14. Gestion sécurité #
La route /api/bms/studio/security permet de lire le mode courant, puis d’envoyer
les actions seal, unseal ou full_access.
Lire le mode de sécurité #
import requests
BASE_URL = "http://127.0.0.1:5000"
r = requests.get(f"{BASE_URL}/api/bms/studio/security", timeout=5)
r.raise_for_status()
print(r.json())
Unseal #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"action": "unseal",
"key1": "0x0414",
"key2": "0x3672"
}
r = requests.post(f"{BASE_URL}/api/bms/studio/security", json=payload, timeout=5)
print(r.status_code)
print(r.json())
Seal #
import requests
BASE_URL = "http://127.0.0.1:5000"
payload = {
"action": "seal"
}
r = requests.post(f"{BASE_URL}/api/bms/studio/security", json=payload, timeout=5)
print(r.status_code)
print(r.json())
15. Exemple complet : outil console simple #
Le script ci-dessous propose un petit utilitaire console regroupant les fonctions les plus utiles : lecture monitoring, diagnostic et cellules.
import json
import requests
class BmsTool:
def __init__(self, base_url="http://127.0.0.1:5000"):
self.base_url = base_url.rstrip("/")
def _get(self, path, params=None, timeout=10):
r = requests.get(f"{self.base_url}{path}", params=params, timeout=timeout)
r.raise_for_status()
return r.json()
def _post(self, path, payload=None, timeout=10):
r = requests.post(f"{self.base_url}{path}", json=payload or {}, timeout=timeout)
r.raise_for_status()
return r.json()
def monitoring(self):
return self._get("/api/bms")
def diag(self):
return self._get("/api/bms/diag")
def cells(self):
return self._get("/api/bms/studio/cells")
if __name__ == "__main__":
tool = BmsTool()
print("=== Monitoring ===")
print(json.dumps(tool.monitoring(), indent=2, ensure_ascii=False))
print("\\n=== Diagnostic ===")
print(json.dumps(tool.diag(), indent=2, ensure_ascii=False))
print("\\n=== Cellules ===")
print(json.dumps(tool.cells(), indent=2, ensure_ascii=False))
16. Bonnes pratiques #
- Commencer par
/api/bmspuis/api/bms/diag. - Utiliser les routes lecture seule avant toute écriture.
- Activer le mode avancé uniquement lorsque nécessaire.
- Journaliser les valeurs lues lors des phases de test et de calibration.
- Valider la cohérence entre le nombre de cellules configuré et le pack réel.
Exemples Python basés sur le plugin API BMS LC30 fourni.
