[TUTO] floorplan, positionnement et dimensionnement de carte en masse via Python

Hello,

Ayant eu la bonne idée de déplacer des cartes en masse sur mon floorplan ( 5286 lignes de yaml )
en les décalant vers le bas, je ne me voyais pas faire ça à la main, du coup j’en ai fait un scrpit python que je partage ici.

Il permettra de jouer sur 1 à 4 valeurs en l’état en % et pas en px ( par sécurité pour moi ) : top, left, height et width

Méthode via machine windows

1. Prérequis : Installer Python si ça n’est pas fait

Pour lire le script, Windows a besoin de « l’interprète » Python.

  1. Allez sur python.org.
  2. Cliquez sur le bouton Download Python 3.x.
  3. IMPORTANT : Lors de l’installation, cochez bien la case « Add Python to PATH » avant de cliquer sur « Install Now ».

il faudra probablement rebooter la machine, puis on vérifie qu’il est installé via une invite de commande > CMD ( dans la barre de recherche )

image

2. Préparation du dossier de travail

  1. Créez un nouveau dossier sur votre Bureau (nommez-le Modif_HA par exemple).
  2. Copiez votre fichier YAML de Home Assistant à l’intérieur (par exemple carte.yaml) via bloc note, vscode …

  1. Créez un nouveau fichier texte dans ce dossier, nommez-le script.py (attention à bien changer l’extension .txt en .py).

  2. Faites un clic droit sur script.py > Modifier (ou ouvrir avec le Bloc-notes) et collez le code que nous avons créé.

script python à coller dans le fichier script.py
import re
import os

def transformer_yaml_universel(input_file, output_file):
    # =================================================================
    # --- CONFIGURATION DES DÉPLACEMENTS (en % uniquement) ---
    # =================================================================
    # Modifie les chiffres ci-dessous selon tes besoins :
    # > Positif pour descendre (top) / aller à droite (left)
    # > Négatif pour monter (top) / aller à gauche (left)
    # > 0 pour ne rien changer
    
    MODIFS = {
        "top":    10,   # Ajustement vertical (Y)
        "left":   0,     # Ajustement horizontal (X)
        "width":  0,     # Ajustement de la largeur
        # "height": 1.5  # <--- EXEMPLE COMMENTÉ : Enlevez le '#' pour activer la hauteur
    }
    # =================================================================

    with open(input_file, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    updated_lines = []
    
    # REGEX : Cherche l'indentation (g1), le mot-clé (g2) et la valeur (g3)
    # Elle ne cible que les valeurs suivies du symbole '%'
    pattern = re.compile(r'^(\s*)(top|left|width|height):\s*(\d+\.?\d*)%')

    for line in lines:
        match = pattern.match(line)
        
        if match:
            indentation = match.group(1)
            cle = match.group(2)
            valeur_actuelle = float(match.group(3))
            
            # On vérifie si la clé existe dans notre dictionnaire MODIFS
            # (Si elle est commentée en haut, elle ne sera pas trouvée ici)
            if cle in MODIFS and MODIFS[cle] != 0:
                nouvelle_valeur = round(valeur_actuelle + MODIFS[cle], 2)
                updated_lines.append(f"{indentation}{cle}: {nouvelle_valeur}%\n")
            else:
                # Si la modif est à 0 ou commentée, on ne touche à rien
                updated_lines.append(line)
        else:
            # Pour toutes les autres lignes (px, textes, entités...), on garde tel quel
            updated_lines.append(line)

    # Sauvegarde du résultat
    with open(output_file, 'w', encoding='utf-8') as f:
        f.writelines(updated_lines)

# --- EXÉCUTION DU SCRIPT ---
if __name__ == "__main__":
    fichier_entree = 'carte.yaml'
    fichier_sortie = 'carte_corrigee.yaml'

    if os.path.exists(fichier_entree):
        transformer_yaml_universel(fichier_entree, fichier_sortie)
        print("-" * 50)
        print("TERMINÉ : Le fichier corrigé est prêt !")
        print("-" * 50)
    else:
        print(f"ERREUR : Placez votre code dans un fichier nommé '{fichier_entree}'")

3. Configuration du script

Avant de le lancer, ouvrez script.py pour régler vos déplacements dans le bloc MODIFS :

  • Descendre de 10% : "top": 10
  • Monter de 5% : "top": -5
  • Décaler à droite : "left": 2.5
  • Désactiver une option : Ajoutez un # devant la ligne (comme c’est le cas pour height dans l’exemple).

4. Lancement du script

C’est ici que la magie opère :

  1. Ouvrez votre dossier Modif_HA. A ce stade il contient 2 fichiers

  1. Dans la barre d’adresse de l’explorateur (là où est écrit le chemin du dossier), tapez cmd et appuyez sur Entrée.

  1. L’invité de commande s’ouvre. Elle est déjà située dans le bon dossier.

  1. Tapez la commande suivante et validez :

python script.py

image

5. Résultat

  • Si tout est bon, le message « TERMINÉ : Le fichier corrigé est prêt ! » s’affiche.

  • Un nouveau fichier nommé carte_corrigee.yaml est apparu dans votre dossier. (F5 au clavier éventuellement dans l’explorateur de fichier).

  • Vous n’avez plus qu’à copier son contenu et le coller dans Home Assistant !
    ici j’ai fait un +10 sur le top (comme dans le code du script qui est donné plus haut).


:light_bulb: Astuces à connaître :

  • Sécurité : Le script ne touche jamais aux valeurs en px (pixels), il ne modifie que ce qui se termine par %.
  • Précision : Les chiffres sont arrondis à 2 décimales pour éviter les bugs d’affichage dans HA (ex: 25.51%).
  • Testez petit à petit : Faites toujours un test sur une copie. Si le déplacement est trop grand, modifiez le chiffre dans le script et relancez-le simplement, il écrasera carte_corrigee.yaml avec les nouvelles valeurs.

Au final, en utilisant ceci (temps de codage en plus), une fois lancé le script prend 1 seconde pour donner le résultat, c’est le temps que ça a pris pour traiter mes 5286 lignes de yaml, idem avec un fichier de 3000 lignes.

bonus je met le script que j’ai utilisé pour traiter mes cartes en masse, sans traiter les custom fields. J’avais besoin de descendre mes cartes hors custom fields

Code
import re
import os

def update_ha_yaml(input_file, output_file):
    with open(input_file, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    updated_lines = []
    # On utilise un drapeau pour savoir si on est à l'intérieur d'un bloc custom_fields
    in_custom_fields = False
    
    # Regex pour trouver "top: 25%" ou "top: 71.6%"
    # Elle capture l'indentation (g1) et la valeur numérique (g2)
    top_pattern = re.compile(r'^(\s*)top:\s*(\d+\.?\d*)%')

    for line in lines:
        stripped = line.strip()
        indent = len(line) - len(line.lstrip())

        # Détection du début d'un custom_fields
        if 'custom_fields:' in line:
            in_custom_fields = True
            cf_indent = indent
        
        # Si on est dans un custom_field, on vérifie si on en sort
        # On en sort si la ligne n'est pas vide et que l'indentation est inférieure ou égale 
        # au mot-clé 'custom_fields', sauf si c'est la ligne du mot-clé lui-même
        elif in_custom_fields and stripped:
            if indent <= cf_indent:
                in_custom_fields = False

        # Modification : si c'est une ligne "top" et qu'on n'est PAS dans custom_fields
        match = top_pattern.match(line)
        if match and not in_custom_fields:
            spaces = match.group(1)
            old_value = float(match.group(2))
            new_value = round(old_value + 6.5, 2)
            updated_lines.append(f"{spaces}top: {new_value}%\n")
        else:
            updated_lines.append(line)

    with open(output_file, 'w', encoding='utf-8') as f:
        f.writelines(updated_lines)

# Lancement du script
if __name__ == "__main__":
    if os.path.exists('carte.yaml'):
        update_ha_yaml('carte.yaml', 'carte_corrigee.yaml')
        print("Succès ! Le fichier 'carte_corrigee.yaml' a été créé.")
    else:
        print("Erreur : Le fichier 'carte.yaml' est introuvable dans le dossier.")

on ne jouera ici que sur la ligne new_value = round(old_value + 6.5, 2) avec ici un +6.5 sur la valeur du top.

Au final un gain de temps considérable pour déplacer / retailler des cartes en masse.

Cdt