[ConcoursDash] 📡 Carte Radar LD2450 — Visualisation interactive des zones de prĂ©sence

Bonjour Ă  tous,
Je viens vous présenter une carte pour calibrer et régler facilement un LD2450. Et sans plus tarder, entrons dans le vif du sujet :

Le problĂšme

Mon LD2450 a perdu toutes ses zones de dĂ©tection suite Ă  une mise Ă  jour. J’ai dĂ» tout reconfigurer
 et lĂ , c’est le drame :sweat_smile:

Configurer un radar LD2450 via les entitĂ©s brutes d’ESPHome, c’est :

  • Des sliders en millimĂštres (essayez de visualiser mentalement « X=2380, Width=2340 Â»â€Š)

  • Aucun retour visuel : impossible de savoir si votre zone couvre le canapĂ© ou le mur d’à cĂŽtĂ©

  • Un aller-retour infernal entre l’interface HA et la piĂšce physique pour vĂ©rifier « est-ce que ça dĂ©tecte lĂ  ? Â»

Je n’ai jamais vraiment trouvĂ© de carte qui me convienne sur les forums. @freetronic a partagĂ© rĂ©cemment une carte sympa pour le LD2410, mais rien que de penser Ă  aller explorer son code :exploding_head:.

Le challenge de faire ma propre carte pendant mes vacances était lancé !

Mon besoin était simple : une carte qui me permette de VOIR mes zones en temps réel pendant que je les ajuste, comme un vrai outil de calibration visuelle intégré à mon dashboard.

La solution : une carte tout-en-un

:one: Tous vos radars sur une seule carte

PlutĂŽt que d’avoir un tableau de bord Ă  rallonge, la carte est entiĂšrement articulĂ©e autour d’un simple input_select (contenant la liste de vos radars LD2450). Ce menu dĂ©roulant permet de basculer instantanĂ©ment d’un capteur Ă  un autre (Salon, Cuisine, Couloir
). Toute l’interface se recharge magiquement avec les paramĂštres et les entitĂ©s spĂ©cifiques de l’appareil sĂ©lectionnĂ© !

:two: Construisez vos zones sur-mesure (et sans effort)

Finis les fastidieux allers-retours dans la piĂšce pour tester votre configuration !

ld2450_creation_zones

  • Ajustement en direct : Les curseurs en bas de carte (Limite Droite, Distance, Largeur, Profondeur) redessinent vos zones gĂ©omĂ©triques en temps rĂ©el sur la carte.

  • Configuration en mĂštres : Tous les rĂ©glages se font en mĂštres (-4 m Ă  +4 m) pour plus de sens (finis les millimĂštres incomprĂ©hensibles).

  • Support de l’inclinaison : Votre capteur n’est pas posĂ© bien droit ? Un curseur d’Angle compense dynamiquement tout le calcul trigonomĂ©trique de l’affichage.

:three: Visualisez vos cibles en temps réel

Testez dynamiquement l’occupation de vos zones avec validation visuelle instantanĂ©e.

ld2450_passages_zones

  • Suivi 2D prĂ©cis : Les cibles (personnes) :green_circle::orange_circle::blue_circle: se dĂ©placent en direct sur le plan quadrillĂ©.

  • RĂ©activitĂ© lumineuse : DĂšs qu’une cible pĂ©nĂštre dans les limites d’une zone, celle-ci s’illumine instantanĂ©ment. C’est l’outil parfait pour vĂ©rifier vos bordures et Ă©viter les dĂ©clenchements parasites.


:hammer_and_wrench: Configuration & Code

Prérequis (HACS)

Pour faire fonctionner cette carte, vous aurez besoin des modules suivants :

  1. Mushroom Cards (pour l’interface de contrîle)

  2. Plotly Graph Card (pour le rendu radar interactif)

  3. Config Template Card (pour la sélection dynamique du capteur)

  4. Stack In Card & Tabbed Card (pour la mise en page propre)

Code YAML de la carte

type: vertical-stack
cards:
  - type: custom:config-template-card
    entities:
      - input_select.liste_esp_ld2450
      - >-
        ${ states['input_select.liste_esp_ld2450'] ? 'binary_sensor.' +
        states['input_select.liste_esp_ld2450'].state + '_radar_any_presence' :
        'sun.sun' }
      - >-
        ${ states['input_select.liste_esp_ld2450'] ? 'binary_sensor.' +
        states['input_select.liste_esp_ld2450'].state + '_radar_zone1_presence' :
        'sun.sun' }
      - >-
        ${ states['input_select.liste_esp_ld2450'] ? 'binary_sensor.' +
        states['input_select.liste_esp_ld2450'].state + '_radar_zone2_presence' :
        'sun.sun' }
      - >-
        ${ states['input_select.liste_esp_ld2450'] ? 'binary_sensor.' +
        states['input_select.liste_esp_ld2450'].state + '_radar_zone3_presence' :
        'sun.sun' }
      - >-
        ${ states['input_select.liste_esp_ld2450'] ? 'binary_sensor.' +
        states['input_select.liste_esp_ld2450'].state + '_radar_zout1_presence' :
        'sun.sun' }
    variables:
      esp: >-
        states['input_select.liste_esp_ld2450'] ?
        states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
    card:
      type: vertical-stack
      cards:
        - type: custom:mushroom-select-card
          entity: input_select.liste_esp_ld2450
          name: Capteur LD2450 Actif
          icon: mdi:radar
          layout: horizontal
        - type: custom:mushroom-entity-card
          entity: ${ 'binary_sensor.' + esp + '_radar_any_presence' }
          name: Détection Globale (Toutes zones)
          icon: mdi:home-account
          icon_color: >-
            ${ states['binary_sensor.' + esp + '_radar_any_presence'].state ===
            'on' ? '#2E8B57' : 'disabled' }
          layout: horizontal
        - type: grid
          columns: 2
          square: false
          cards:
            - type: custom:mushroom-entity-card
              entity: ${ 'binary_sensor.' + esp + '_radar_zone1_presence' }
              name: Zone 1
              icon: mdi:square-outline
              icon_color: >-
                ${ states['binary_sensor.' + esp +
                '_radar_zone1_presence']?.state === 'on' ? '#2E8B57' :
                'disabled' }
            - type: custom:mushroom-entity-card
              entity: ${ 'binary_sensor.' + esp + '_radar_zone2_presence' }
              name: Zone 2
              icon: mdi:square-outline
              icon_color: >-
                ${ states['binary_sensor.' + esp +
                '_radar_zone2_presence']?.state === 'on' ? '#2E8B57' :
                'disabled' }
            - type: custom:mushroom-entity-card
              entity: ${ 'binary_sensor.' + esp + '_radar_zone3_presence' }
              name: Zone 3
              icon: mdi:square-outline
              icon_color: >-
                ${ states['binary_sensor.' + esp +
                '_radar_zone3_presence']?.state === 'on' ? '#2E8B57' :
                'disabled' }
            - type: custom:mushroom-entity-card
              entity: ${ 'binary_sensor.' + esp + '_radar_zout1_presence' }
              name: Exclusion
              icon: mdi:shield-off-outline
              icon_color: >-
                ${ states['binary_sensor.' + esp +
                '_radar_zout1_presence']?.state === 'on' ? '#2E8B57' :
                'disabled' }
  - type: custom:plotly-graph
    title: Visualisation Temps Réel
    refresh_interval: 1
    hours_to_show: current_day
    ha_theme: true
    layout:
      height: 400
      margin:
        l: 30
        r: 30
        t: 30
        b: 30
      xaxis:
        type: number
        range:
          - -4
          - 4
        dtick: 1
        gridcolor: RGBA(200,200,200,0.1)
        zerolinecolor: RGBA(200,200,200,0.2)
        fixedrange: true
      yaxis:
        type: number
        range:
          - 8
          - 0
        dtick: 1
        gridcolor: RGBA(200,200,200,0.1)
        zerolinecolor: RGBA(200,200,200,0.2)
        fixedrange: true
        scaleanchor: x
        scaleratio: 1
    entities:
      - entity: ""
        name: Cible 1
        mode: markers
        marker:
          size: 15
          color: "#2E8B57"
          symbol: circle
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target1_x']?.state?.replace(',', '.') || 0) ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target1_y']?.state?.replace(',', '.') || 0) ];
          }
      - entity: ""
        name: Cible 2
        mode: markers
        marker:
          size: 12
          color: orange
          symbol: circle
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target2_x']?.state?.replace(',', '.') || 0) ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target2_y']?.state?.replace(',', '.') || 0) ];
          }
      - entity: ""
        name: Cible 3
        mode: markers
        marker:
          size: 12
          color: blue
          symbol: circle
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target3_x']?.state?.replace(',', '.') || 0) ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            return [ Number(hass.states['sensor.'+esp+'_radar_target3_y']?.state?.replace(',', '.') || 0) ];
          }
      - entity: ""
        name: Zone 1
        mode: lines
        fill: toself
        fillcolor: >-
          $ex hass.states['binary_sensor.' +
          (hass.states['input_select.liste_esp_ld2450'] ?
          hass.states['input_select.liste_esp_ld2450'].state : 'esp_salon02') +
          '_radar_zone1_presence'].state === 'on' ? 'RGBA(46,139,87,0.4)' :
          'RGBA(46,139,87,0.1)'
        line:
          color: RGBA(46,139,87,0.8)
          width: 2
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zx = Number(hass.states['number.'+esp+'_radar_zone1_x']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone1_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone1_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) - 90) * Math.PI / 180;
            return [ zx, zx - zw * Math.cos(angle), zx - zw * Math.cos(angle) + zh * Math.cos(angle90), zx + zh * Math.cos(angle90), zx ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zy = Number(hass.states['number.'+esp+'_radar_zone1_y']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone1_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone1_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) + 90) * Math.PI / 180;
            return [ zy, zy + zw * Math.sin(angle), zy + zw * Math.sin(angle) + zh * Math.sin(angle90), zy + zh * Math.sin(angle90), zy ];
          }
      - entity: ""
        name: Zone 2
        mode: lines
        fill: toself
        fillcolor: >-
          $ex hass.states['binary_sensor.' +
          (hass.states['input_select.liste_esp_ld2450'] ?
          hass.states['input_select.liste_esp_ld2450'].state : 'esp_salon02') +
          '_radar_zone2_presence'].state === 'on' ? 'RGBA(255,165,0,0.4)' :
          'RGBA(255,165,0,0.1)'
        line:
          color: RGBA(255,165,0,0.8)
          width: 2
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zx = Number(hass.states['number.'+esp+'_radar_zone2_x']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone2_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone2_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) - 90) * Math.PI / 180;
            return [ zx, zx - zw * Math.cos(angle), zx - zw * Math.cos(angle) + zh * Math.cos(angle90), zx + zh * Math.cos(angle90), zx ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zy = Number(hass.states['number.'+esp+'_radar_zone2_y']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone2_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone2_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) + 90) * Math.PI / 180;
            return [ zy, zy + zw * Math.sin(angle), zy + zw * Math.sin(angle) + zh * Math.sin(angle90), zy + zh * Math.sin(angle90), zy ];
          }
      - entity: ""
        name: Zone 3
        mode: lines
        fill: toself
        fillcolor: >-
          $ex hass.states['binary_sensor.' +
          (hass.states['input_select.liste_esp_ld2450'] ?
          hass.states['input_select.liste_esp_ld2450'].state : 'esp_salon02') +
          '_radar_zone3_presence'].state === 'on' ? 'RGBA(0,0,255,0.4)' :
          'RGBA(0,0,255,0.1)'
        line:
          color: RGBA(0,0,255,0.8)
          width: 2
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zx = Number(hass.states['number.'+esp+'_radar_zone3_x']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone3_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone3_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) - 90) * Math.PI / 180;
            return [ zx, zx - zw * Math.cos(angle), zx - zw * Math.cos(angle) + zh * Math.cos(angle90), zx + zh * Math.cos(angle90), zx ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zy = Number(hass.states['number.'+esp+'_radar_zone3_y']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zone3_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zone3_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) + 90) * Math.PI / 180;
            return [ zy, zy + zw * Math.sin(angle), zy + zw * Math.sin(angle) + zh * Math.sin(angle90), zy + zh * Math.sin(angle90), zy ];
          }
      - entity: ""
        name: Exclusion 1
        mode: lines
        fill: toself
        fillcolor: >-
          $ex hass.states['binary_sensor.' +
          (hass.states['input_select.liste_esp_ld2450'] ?
          hass.states['input_select.liste_esp_ld2450'].state : 'esp_salon02') +
          '_radar_zout1_presence'].state === 'on' ? 'RGBA(255,0,0,0.4)' :
          'RGBA(255,0,0,0.1)'
        line:
          color: RGBA(255,0,0,0.8)
          width: 2
          dash: dash
        x: |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zx = Number(hass.states['number.'+esp+'_radar_zout1_x']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zout1_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zout1_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) - 90) * Math.PI / 180;
            return [ zx, zx - zw * Math.cos(angle), zx - zw * Math.cos(angle) + zh * Math.cos(angle90), zx + zh * Math.cos(angle90), zx ];
          }
        "y": |
          $fn ({hass}) => {
            let esp = hass.states['input_select.liste_esp_ld2450']?.state || 'esp_salon02';
            let zy = Number(hass.states['number.'+esp+'_radar_zout1_y']?.state?.replace(',', '.') || 0);
            let zw = Number(hass.states['number.'+esp+'_radar_zout1_width']?.state?.replace(',', '.') || 0);
            let zh = Number(hass.states['number.'+esp+'_radar_zout1_height']?.state?.replace(',', '.') || 0);
            let angle = Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) * Math.PI / 180;
            let angle90 = (Number(hass.states['number.'+esp+'_radar_angle']?.state?.replace(',', '.') || 0) + 90) * Math.PI / 180;
            return [ zy, zy + zw * Math.sin(angle), zy + zw * Math.sin(angle) + zh * Math.sin(angle90), zy + zh * Math.sin(angle90), zy ];
          }
  - type: vertical-stack
    cards:
      - type: custom:config-template-card
        entities:
          - input_select.liste_esp_ld2450
          - >-
            ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_angle' : 'sun.sun' }
        variables:
          esp: >-
            states['input_select.liste_esp_ld2450'] ? states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
        card:
          type: custom:mushroom-number-card
          entity: ${ 'number.' + esp + '_radar_angle' }
          name: Angle d'inclinaison du radar
          icon: mdi:angle-acute
      - type: custom:tabbed-card
        tabs:
          - attributes:
              label: Zone 1
            card:
              type: custom:config-template-card
              entities:
                - input_select.liste_esp_ld2450
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone1_x' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone1_y' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone1_width' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone1_height' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone1_timeout' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'switch.' + states['input_select.liste_esp_ld2450'].state + '_radar_target_must_leave_zone1' : 'sun.sun' }
              variables:
                esp: >-
                  states['input_select.liste_esp_ld2450'] ? states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
              card:
                type: grid
                columns: 2
                square: false
                cards:
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone1_x' }
                    name: Limite Droite (X)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone1_y' }
                    name: Distance Initiale (Y)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone1_width' }
                    name: Expansion Gauche (Largeur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone1_height' }
                    name: Profondeur (Longueur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone1_timeout' }
                    name: Timeout
                    display_mode: buttons
                  - type: custom:mushroom-entity-card
                    entity: ${ 'switch.' + esp + '_radar_target_must_leave_zone1' }
                    name: Rester Actif (Sortie)
                    icon: mdi:account-cancel
                    icon_color: >-
                      ${ states['switch.' + esp + '_radar_target_must_leave_zone1']?.state === 'on' ? '#2E8B57' : 'disabled' }
                    tap_action:
                      action: toggle
          - attributes:
              label: Zone 2
            card:
              type: custom:config-template-card
              entities:
                - input_select.liste_esp_ld2450
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone2_x' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone2_y' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone2_width' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone2_height' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone2_timeout' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'switch.' + states['input_select.liste_esp_ld2450'].state + '_radar_target_must_leave_zone2' : 'sun.sun' }
              variables:
                esp: >-
                  states['input_select.liste_esp_ld2450'] ? states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
              card:
                type: grid
                columns: 2
                square: false
                cards:
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone2_x' }
                    name: Limite Droite (X)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone2_y' }
                    name: Distance Initiale (Y)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone2_width' }
                    name: Expansion Gauche (Largeur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone2_height' }
                    name: Profondeur (Longueur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone2_timeout' }
                    name: Timeout
                    display_mode: buttons
                  - type: custom:mushroom-entity-card
                    entity: ${ 'switch.' + esp + '_radar_target_must_leave_zone2' }
                    name: Rester Actif (Sortie)
                    icon: mdi:account-cancel
                    icon_color: >-
                      ${ states['switch.' + esp + '_radar_target_must_leave_zone2']?.state === 'on' ? '#2E8B57' : 'disabled' }
                    tap_action:
                      action: toggle
          - attributes:
              label: Zone 3
            card:
              type: custom:config-template-card
              entities:
                - input_select.liste_esp_ld2450
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone3_x' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone3_y' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone3_width' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone3_height' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zone3_timeout' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'switch.' + states['input_select.liste_esp_ld2450'].state + '_radar_target_must_leave_zone3' : 'sun.sun' }
              variables:
                esp: >-
                  states['input_select.liste_esp_ld2450'] ? states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
              card:
                type: grid
                columns: 2
                square: false
                cards:
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone3_x' }
                    name: Limite Droite (X)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone3_y' }
                    name: Distance Initiale (Y)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone3_width' }
                    name: Expansion Gauche (Largeur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone3_height' }
                    name: Profondeur (Longueur)
                  - type: custom:mushroom-number-card
                    entity: ${ 'number.' + esp + '_radar_zone3_timeout' }
                    name: Timeout
                    display_mode: buttons
                  - type: custom:mushroom-entity-card
                    entity: ${ 'switch.' + esp + '_radar_target_must_leave_zone3' }
                    name: Rester Actif (Sortie)
                    icon: mdi:account-cancel
                    icon_color: >-
                      ${ states['switch.' + esp + '_radar_target_must_leave_zone3']?.state === 'on' ? '#2E8B57' : 'disabled' }
                    tap_action:
                      action: toggle
          - attributes:
              label: Exclusion 1
            card:
              type: custom:config-template-card
              entities:
                - input_select.liste_esp_ld2450
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'switch.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_enable' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_x' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_y' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_width' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_height' : 'sun.sun' }
                - >-
                  ${ states['input_select.liste_esp_ld2450'] ? 'number.' + states['input_select.liste_esp_ld2450'].state + '_radar_zout1_timeout' : 'sun.sun' }
              variables:
                esp: >-
                  states['input_select.liste_esp_ld2450'] ? states['input_select.liste_esp_ld2450'].state : 'esp_salon02'
              card:
                type: vertical-stack
                cards:
                  - type: custom:mushroom-entity-card
                    entity: ${ 'switch.' + esp + '_radar_zout1_enable' }
                    name: Activer Exclusion
                    icon_color: >-
                      ${ states['switch.' + esp + '_radar_zout1_enable']?.state === 'on' ? '#2E8B57' : 'disabled' }
                    tap_action:
                      action: toggle
                  - type: grid
                    columns: 2
                    square: false
                    cards:
                      - type: custom:mushroom-number-card
                        entity: ${ 'number.' + esp + '_radar_zout1_x' }
                        name: Limite Droite (X)
                      - type: custom:mushroom-number-card
                        entity: ${ 'number.' + esp + '_radar_zout1_y' }
                        name: Distance Initiale (Y)
                      - type: custom:mushroom-number-card
                        entity: ${ 'number.' + esp + '_radar_zout1_width' }
                        name: Expansion Gauche (Largeur)
                      - type: custom:mushroom-number-card
                        entity: ${ 'number.' + esp + '_radar_zout1_height' }
                        name: Profondeur (Longueur)
                      - type: custom:mushroom-number-card
                        entity: ${ 'number.' + esp + '_radar_zout1_timeout' }
                        name: Timeout
                        display_mode: buttons

:open_file_folder: Code Source & GitHub

Pour ne pas surcharger ce post avec d’interminables dĂ©tails techniques (l’explication du code Javascript de la carte Plotly, ou nos modifications apportĂ©es au code ESPHome)
 j’ai tout centralisĂ© et documentĂ© pas-Ă -pas sur GitHub.

Vous y trouverez les prérequis, le firmware .ld2450.yaml adapté, et la fameuse carte à copier-coller :

:open_file_folder: Découvrir le projet et la carte sur GitHub


NB (Concours Dashboard) : Comme il ne fallait choisir qu’une seule carte pour la participation au concours, j’ai sĂ©lectionnĂ© le LD2450. Mais pour info, sachez qu’un travail en cours est actuellement menĂ© pour dĂ©cliner cette exacte mĂȘme philosophie d’interface de calibration (visuelle et multi-ESP) sur le LD2410. Le chantier est visible sur le dĂ©pĂŽt global ha-ld24xx-radars si les curieux veulent dĂ©jĂ  y jeter un Ɠil !

15 « J'aime »

Hello,

ce ne sont que quelques lignes de code :smiley: du coup faudra que j’upgarde mon template pour ajoutĂ© l’input select, aucune idĂ©e de pourquoi je n’y avait pas pensĂ©, mais c’est tellement logique 
 le template avait dĂ» cramer quelques neurones au passage :smiley:

cdt

Bonjour @Gael, @freetronic
J’utilise actuellement un LD2410, j’ai des LD2450 en attente donc cette carte m’intĂ©resse beaucoup.
Si au passage vous aviez trouvé un boßtier à imprimer en 3D, ESP32 30 pins + LD2450 / LD2410, je prends aussi :wink:

Bob

Hello,

J’en avais fait, mon seul conseil, n’utilise pas de PLA, au final j’ai achetĂ© des boitiers apacher

Sinon c’est la carte de @Gael mĂȘme si j’ai insufflĂ© l’idĂ©e avec mes template streamline de la mort :smiley:

cdt

Salut @freetronic
je n’utilise que du CR-PETG.
Et tes boĂźtiers Ă  pas cher tu les trouves oĂč ?
Je trouves des sources pour mettre tous ça en boßtier mais pas pour des 30 pins, sinon je prendrai des ESP de petite petite taille style, C, D1 MINI.

Merci
Bob

Re,

C’était sur ali, mais je n’ai pas la ref en tĂȘte, tout dĂ©pend des capteurs que tu utilises et de l’intĂ©gration que tu veux obtenir ( attention Ă  la chauffe et aux perturbations Ă©lectromagnĂ©tiques si les capteurs sont trop proches, attention si un capteur de tempĂ©rature est utilisĂ© trop proche, il faudra utiliser l’offset pour le calibrer

je reviens vers toi si je retrouve la ref

cdt

Edit ça va ĂȘtre compliquĂ© je n’ai rien dans mon historique de commande 


1 « J'aime »

j’ai pas d’imprimante 3D encore, donc non, moi j’ai des fils partout et je m’en fou :smiley:

1 « J'aime »

Re,

ça devait ĂȘtre ça ou s’en approchant https://fr.aliexpress.com/item/1005008293099350.html?spm=a2g0o.productlist.main.14.49fc34d34ZC4Jw&algo_pvid=71e87d65-4f93-4a6d-b787-e73145bd4e8e&algo_exp_id=71e87d65-4f93-4a6d-b787-e73145bd4e8e-4&pdp_ext_f={« order Â»%3A"54"%2C"eval"%3A"1"%2C"fromPage"%3A"search"}&pdp_npi=6%40dis!EUR!1.37!1.37!!!10.69!10.69!%40211b819117775458474707432e1d6a!12000044514590029!sea!FR!7988737945!ABX!1!0!n_tag%3A-29910%3Bd%3Acd787b8%3Bm03_new_user%3A-29895&curPageLogUid=pH0w1V95xSsX&utparam-url=scene%3Asearch|query_from%3A|x_object_id%3A1005008293099350|_p_origin_prod%3A

c’est la mĂȘme taille en tout cas 61x36x25mm

cdt

@Gael
si besoin, je peux imprimer en PETG

et bravo pour la carte, mĂȘme si je n’en ai pas l’usage

1 « J'aime »