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 ![]()
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
.
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
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é !
Construisez vos zones sur-mesure (et sans effort)
Finis les fastidieux allers-retours dans la piĂšce pour tester votre configuration !

-
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.
Visualisez vos cibles en temps réel
Testez dynamiquement l'occupation de vos zones avec validation visuelle instantanée.

-
Suivi 2D précis : Les cibles (personnes)


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.
Configuration & Code
Prérequis (HACS)
Pour faire fonctionner cette carte, vous aurez besoin des modules suivants :
-
Mushroom Cards (pour l'interface de contrĂŽle)
-
Plotly Graph Card (pour le rendu radar interactif)
-
Config Template Card (pour la sélection dynamique du capteur)
-
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
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 :
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 !

