View Categories

BMS LC30 – Exemples Python complets

10 min read

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())
Attention : réserver ces opérations aux cas de maintenance ou de développement maîtrisé.

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())
Attention : l’écriture Data Flash requiert le mode avancé et doit être réservée aux opérations maîtrisées.

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/bms puis /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.

Powered by BetterDocs

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut