Carte suivi de charge / On/Off de la prise connectée LEXMAN (Cupra Formentor)

Salut à tous :waving_hand:

Je partage une deuxième petite carte que j'ai réalisée pour mon dashboard Home Assistant.

Cette fois, l'idée était d'avoir un affichage simple pour suivre la recharge de ma voiture hybride rechargeable, une Cupra Formentor, et de pouvoir allumer et éteindre la prise en cliquant sur la carte.

Je suis frustré depuis un moment de ne pas avoir littéralement le contrôle de mon app mobile Cupra. Donc j'ai essayé de faire quelque chose qui correspond à la voiture mais qui reste adaptable pour tous.

La carte permet de voir en un coup d'œil :

:electric_plug: si la prise est allumée ou éteinte
:high_voltage: la puissance instantanée consommée
:battery: l'état de la recharge
:bar_chart: l'énergie totale consommée
:control_knobs: et surtout, de piloter directement la prise depuis la carte

Le tout avec un affichage assez minimaliste pour rester cohérent avec le reste de mon dashboard.

Comment ça fonctionne ?

Dans mon installation, la voiture est branchée sur une prise connectée, qui me remonte la consommation et peut être pilotée dans Home Assistant :

  • l'état ON/OFF de la prise
  • la puissance instantanée en watts
  • l'énergie consommée en kWh

La carte utilise ces trois informations pour déterminer automatiquement l'état de la recharge.

Les trois états affichés

Lorsque la prise est désactivée :

  • ÉTEINTE

PRISE ALLUMÉE mais consommation faible

Lorsque la prise est allumée mais que la consommation est inférieure à 100 W :

  • CHARGÉ

Cela permet notamment de considérer que la voiture a terminé sa charge.

PRISE ALLUMÉE avec une consommation supérieure à 100 W

La carte affiche :

  • EN CHARGE

avec la couleur orange correspondante.

Les éléments à modifier

C'est probablement la partie la plus importante si vous souhaitez adapter la carte à votre installation.

Au début du code, j'ai regroupé les trois entités utilisées :

const switchEntity =
  'switch.0x705464fffe445e61';


const powerEntity =
  'sensor.0x705464fffe445e61_power';


const energyEntity =
  'sensor.0x705464fffe445e61_energy';

1. Entité de la prise

Remplacez :

switch.0x705464fffe445e61

par l'entité de votre prise connectée.

Par exemple :

switch.prise_garage

Cette entité sert à connaître l'état de la prise et permet également de l'allumer/éteindre directement depuis le petit bouton en haut à droite.

2. Entité de puissance

Remplacez :

sensor.0x705464fffe445e61_power

par votre capteur de puissance.

Celui-ci doit idéalement remonter une valeur en watts (W).

C'est cette valeur qui est affichée en gros au centre de la carte.

3. Entité d'énergie

Remplacez :

sensor.0x705464fffe445e61_energy

par votre capteur d'énergie.

La valeur est affichée en kWh en bas de la carte.

4. Modifier le seuil "CHARGÉ"

Par défaut, j'ai choisi 100 W comme seuil :

} else if (power < 100) {


  chargeStatus = 'CHARGÉ';
  chargeClass = 'charged';


} else {


  chargeStatus = 'EN CHARGE';
  chargeClass = 'charging';
}

Donc :

Situation Affichage
Prise OFF ÉTEINTE
Prise ON + < 100 W CHARGÉ
Prise ON + ≥ 100 W EN CHARGE

Ce seuil est évidemment à adapter à votre véhicule et à votre prise.

Par exemple, si votre voiture consomme toujours quelques dizaines de watts même lorsqu'elle a terminé sa charge, 100 W peut être un seuil intéressant.

Si vous souhaitez être plus ou moins sensible, il suffit de modifier :

power < 100

par exemple en :

power < 50

ou :

power < 200

5. Modifier les couleurs

La couleur principale de la carte est actuellement Cuivre :

#c87941

Elle est utilisée notamment pour :

la bordure
le logo
le toggle
le texte EN CHARGE

Vous pouvez donc facilement remplacer cette couleur par celle de votre choix.

Par exemple, pour quelque chose de plus "électrique", vous pouvez remplacer #c87941 par une couleur bleue ou verte.

6. Modifier le nom de la voiture

Le nom est simplement écrit en dur dans la carte :

<div class="cname">
  Cupra Formentor
</div>

Vous pouvez donc mettre ce que vous voulez :

<div class="cname">
  Tesla Model 3
</div>

ou :

<div class="cname">
  Peugeot 308 Hybrid
</div>

Même chose pour le petit sous-titre :

<div class="csub">
  GARAGE · PRISE DÉDIÉE
</div>

7. Le bouton en haut à droite

Le petit interrupteur n'est pas simplement décoratif.

Il permet réellement de basculer la prise ON/OFF.

La carte utilise :

hass.callService(
  'switch',
  'toggle',
  {
    entity_id: switchEntity
  }
);

Il faut donc que l'entité définie dans switchEntity soit bien une entité de type switch.

:package: Pré-requis

Comme pour ma précédente carte, celle-ci utilise :

custom:button-card
card-mod

Il suffit ensuite de créer une carte manuelle dans votre dashboard Lovelace et de coller le code.

type: custom:button-card
show_name: false
show_icon: false
show_state: false

# ============================================================
# ENTITÉ PRINCIPALE : PRISE / CHARGEUR
# ============================================================

entity: switch.0x705464fffe445e61

tap_action:
  action: toggle

# ============================================================
# STYLE DE LA CARTE
# ============================================================

card_mod:
  style: |
    ha-card {
      border: 1.5px solid #c87941 !important;
      border-radius: 16px !important;
    }

styles:
  card:
    - padding: 0
    - background: '#ffffff'
    - border-radius: 16px
    - overflow: hidden
    - text-align: left
    - height: 285px

  grid:
    - grid-template-areas: '"content"'
    - grid-template-columns: 1fr
    - grid-template-rows: auto

  custom_fields:
    content:
      - width: 100%
      - display: block
      - padding: 0
      - margin: 0
      - text-align: left

custom_fields:
  content: |
    [[[
      // ==========================================================
      // ENTITÉS À ADAPTER À VOTRE INSTALLATION
      // ==========================================================
      //
      // Prise / chargeur :
      // switch.0x705464fffe445e61
      //
      // Puissance instantanée :
      // sensor.0x705464fffe445e61_power
      //
      // Énergie totale :
      // sensor.0x705464fffe445e61_energy
      //
      // ==========================================================

      const switchEntity =
        'switch.0x705464fffe445e61';

      const powerEntity =
        'sensor.0x705464fffe445e61_power';

      const energyEntity =
        'sensor.0x705464fffe445e61_energy';

      // ==========================================================
      // VALEURS
      // ==========================================================

      const switchState =
        states[switchEntity].state;

      const power =
        parseFloat(
          states[powerEntity].state
        ) || 0;

      const energy =
        parseFloat(
          states[energyEntity].state
        ) || 0;

      // ==========================================================
      // STATUT DE CHARGE
      // ==========================================================
      //
      // Prise éteinte       → ÉTEINTE
      // Prise allumée + <100W → CHARGÉ
      // Prise allumée + ≥100W → EN CHARGE
      //
      // Le seuil de 100 W peut être modifié ci-dessous.
      // ==========================================================

      let chargeStatus;
      let chargeClass;

      if (switchState !== 'on') {

        chargeStatus = 'ÉTEINTE';
        chargeClass = 'off';

      } else if (power < 100) {

        chargeStatus = 'CHARGÉ';
        chargeClass = 'charged';

      } else {

        chargeStatus = 'EN CHARGE';
        chargeClass = 'charging';
      }

      // ==========================================================
      // HTML
      // ==========================================================

      return `

        <style>

          /* ======================================================
             RESET
             ====================================================== */

          .cw * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
          }

          .cw {
            font-family: sans-serif;
            color: #1a1917;
            width: 100%;
            display: block;
          }

          /* ======================================================
             PARTIE HAUTE
             ====================================================== */

          .ch {
            padding: 1rem 1.25rem 2rem;
          }

          /* ======================================================
             EN-TÊTE
             ====================================================== */

          .cht {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            margin-bottom: 2.9rem;
          }

          .cbrand {
            display: flex;
            align-items: center;
            gap: 10px;
          }

          /* Cercle contenant le logo */

          .cmark {
            width: 38px;
            height: 38px;
            border-radius: 50%;
            background: #fdf6ee;
            border: 1px solid #c87941;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
          }

          /* Nom de la voiture */

          .cname {
            font-size: 14px;
            font-weight: 500;
            color: #1a1917;
            letter-spacing: 0.03em;
          }

          /* Sous-titre */

          .csub {
            font-size: 10px;
            color: #9a9590;
            letter-spacing: 0.06em;
            margin-top: 2px;
          }

          /* ======================================================
             TOGGLE
             ====================================================== */

          .ctrow {
            display: flex;
            flex-direction: column;
            align-items: flex-end;
            gap: 8px;
          }

          .ctoggle {
            position: relative;
            width: 38px;
            height: 20px;
            cursor: pointer;
            flex-shrink: 0;
            z-index: 999;
          }

          .cslider {
            position: absolute;
            inset: 0;
            border-radius: 20px;
            transition: 0.2s;
          }

          .cthumb {
            position: absolute;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            top: 3px;
            transition: 0.2s;
          }

          /* ======================================================
             PUISSANCE + STATUT
             ====================================================== */

          .cpwr-row {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
          }

          .cprow {
            display: flex;
            align-items: baseline;
            gap: 5px;
          }

          /* Valeur de puissance */

          .cpval {
            font-size: 48px;
            font-weight: 500;
            color: #1a1917;
            line-height: 1;
            letter-spacing: -0.02em;
          }

          /* Unité W */

          .cpunit {
            font-size: 20px;
            color: #9a9590;
          }

          /* Statut de charge */

          .ccharge-status {
            font-size: 20px;
            line-height: 1;
            font-weight: 500;
            letter-spacing: 0.06em;
            white-space: nowrap;
            text-align: right;
          }

          /* En charge */

          .ccharge-status.charging {
            color: #c87941;
          }

          /* Batterie chargée */

          .ccharge-status.charged {
            color: #9a9590;
          }

          /* Prise éteinte */

          .ccharge-status.off {
            color: #9a9590;
          }

          /* Libellé sous la puissance */

          .cplbl {
            font-size: 10px;
            color: #c87941;
            letter-spacing: 0.12em;
            margin-top: 6px;
          }

          /* ======================================================
             PARTIE BASSE : ÉNERGIE TOTALE
             ====================================================== */

          .cmets {
            border-top: 0.5px solid #e0ddd8;
            padding: 1rem 1.25rem 1.2rem;
          }

          .cmlbl {
            font-size: 10px;
            color: #9a9590;
            letter-spacing: 0.1em;
            margin-bottom: 6px;
          }

          .cmval {
            font-size: 24px;
            font-weight: 500;
            color: #1a1917;
          }

          .cmunit {
            font-size: 13px;
            color: #9a9590;
            margin-left: 2px;
          }

        </style>


        <div class="cw">

          <!-- ====================================================
               EN-TÊTE
               ==================================================== -->

          <div class="ch">

            <div class="cht">

              <!-- Marque + nom -->

              <div class="cbrand">

                <div class="cmark">

                  <!-- Logo Cupra -->

                  <svg
                    width="26"
                    height="17"
                    viewBox="64 0 182 140"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >

                    <path
                      fill="#c87941"
                      d="M208.415,28.817c-9.839,4.816-19.677,9.632-29.516,14.445h-0.007c5.999,2.295,11.995,4.599,17.988,6.911c3.712,1.431,8.115,3.227,9.735,7.613c1.665,4.503-0.784,8.521-2.948,11.909c-3.275,5.129-6.55,10.258-9.825,15.384c-11.651,18.246-23.31,36.492-35.006,54.711c-0.021-5.624-0.034-11.252-0.045-16.877v-0.01c4.472-14.066,8.837-28.164,13.048-42.313c1.194-4.018,2.377-8.039,3.543-12.064c0.702-2.425,0.248-3.877-2.085-5.033c-5.958-2.941-11.92-5.879-17.885-8.813c-5.962,2.934-11.923,5.872-17.885,8.813c-2.332,1.156-2.786,2.608-2.085,5.033c1.17,4.025,2.35,8.046,3.547,12.064c4.207,14.149,8.573,28.246,13.048,42.313l-0.003,0.01c-0.01,5.624-0.024,11.252-0.045,16.877c-11.696-18.219-23.351-36.465-35.006-54.711c-3.275-5.126-6.55-10.255-9.821-15.384c-2.164-3.388-4.617-7.406-2.952-11.909c1.624-4.386,6.024-6.182,9.735-7.613c5.993-2.312,11.989-4.617,17.988-6.911h-0.003c-9.842-4.813-19.681-9.629-29.519-14.445l-0.014-0.014c3.072,5.139,6.137,10.282,9.202,15.425c-5.074,1.947-10.145,3.894-15.215,5.848C85.732,33.393,75.072,16.712,64.456,0c30.286,10.743,60.545,21.569,90.958,31.951C185.831,21.569,216.086,10.743,246.376,0c-10.616,16.712-21.28,33.393-31.934,50.077c-5.067-1.954-10.141-3.901-15.215-5.848c3.065-5.143,6.134-10.286,9.202-15.425"
                    />

                  </svg>

                </div>

                <div>

                  <div class="cname">
                    Cupra Formentor
                  </div>

                  <div class="csub">
                    GARAGE · PRISE DÉDIÉE
                  </div>

                </div>

              </div>


              <!-- ==================================================
                   TOGGLE DE LA PRISE
                   ================================================== -->

              <div class="ctrow">

                <div
                  class="ctoggle"
                  id="cupra-toggle"
                >

                  <span
                    class="cslider"
                    style="
                      background:${switchState === 'on'
                        ? '#fdf0e0'
                        : '#f0ede8'};

                      border:0.5px solid ${switchState === 'on'
                        ? '#c87941'
                        : '#d0cdc8'}
                    "
                  >
                  </span>

                  <span
                    class="cthumb"
                    style="
                      left:${switchState === 'on'
                        ? '21'
                        : '3'}px;

                      background:${switchState === 'on'
                        ? '#c87941'
                        : '#b0ada8'}
                    "
                  >
                  </span>

                </div>

              </div>

            </div>


            <!-- ==================================================
                 PUISSANCE + STATUT DE CHARGE
                 ================================================== -->

            <div class="cpwr-row">

              <div class="cprow">

                <span class="cpval">
                  ${Math.round(power)}
                </span>

                <span class="cpunit">
                  W
                </span>

              </div>


              <div class="ccharge-status ${chargeClass}">

                ${chargeStatus}

              </div>

            </div>


            <div class="cplbl">
              PUISSANCE INSTANTANÉE
            </div>

          </div>


          <!-- ====================================================
               ÉNERGIE TOTALE
               ==================================================== -->

          <div class="cmets">

            <div class="cmlbl">
              ⚡ ÉNERGIE TOTALE
            </div>

            <div class="cmval">

              ${energy.toFixed(1)}

              <span class="cmunit">
                kWh
              </span>

            </div>

          </div>

        </div>


        <!-- ======================================================
             GESTION DU BOUTON TOGGLE
             ====================================================== -->

        <script>

          (function() {

            const toggle =
              document.getElementById(
                'cupra-toggle'
              );

            if (
              toggle &&
              !toggle.dataset.bound
            ) {

              toggle.dataset.bound = '1';

              toggle.addEventListener(
                'click',
                function(e) {

                  e.preventDefault();
                  e.stopImmediatePropagation();

                  hass.callService(
                    'switch',
                    'toggle',
                    {
                      entity_id:
                        switchEntity
                    }
                  );

                }
              );
            }

          })();

        </script>

      `;
    ]]]

Salut @Petit-LU

Penses à refaire un tour sur la mise en page, tu as perdu plein de choses avec le copié/collé simple

Salut @Pulpy-Luke ,

Merci pour ton retour, j'étais dessus figure toi ^^
Est ce que c'est mieux comme ça ?

oui, il reste quelques soucis sur les titres/numérotation