Ah, j’ai testé avec un number test ça me semblait ok mais du coup tu peux m’en dire plus, là malheureusement c’est au dessus de mes compétences actuelles
Teste ça :
type: custom:button-card
entity: input_number.test_temp
show_state: false
show_icon: false
show_name: false
tap_action: none
double_tap_action: none
hold_action: none
custom_fields:
icon:
card:
type: custom:button-card
icon: mdi:thermometer
styles:
card:
- aspect-ratio: 1/1
- width: 25px
- padding: 0
- border: 1px solid white
- border-radius: 50%
- background: none
icon:
- width: 90%
- color: white
name:
card:
type: custom:button-card
name: Netatmo Salon Température
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1rem
- align-self: start
- justify-self: start
- color: white
- font-weight: 500
bar:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- height: 6px
- width: 250px
- border-radius: 999px
- border: 0
- padding: 0
- background: |-
linear-gradient(to right,
rgba(255,0,0,1.0) 0%,
rgba(255,255,0,1.0) 12.5%,
rgba(0,255,0,1.0) 50%,
rgba(255,255,0,1.0) 62.5%,
rgba(255,120,0,1.0) 75%,
rgba(255,0,0,1.0) 100%)
cursor:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- width: 12px
- height: 25px
- border-radius: 999px
- border: 4px solid rgba(42,45,54,1.0)
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state) || minTemp;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
value:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: true
state_display: |
[[[
const v = Number(entity.state);
return isNaN(v) ? '—' : v.toFixed(1);
]]]
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
state:
- color: white
- font-size: 1.8rem
- font-weight: 700
unit:
card:
type: custom:button-card
name: °C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.3rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 800
min_val:
card:
type: custom:button-card
name: 14°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.0rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
max_val:
card:
type: custom:button-card
name: 30°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.0rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
comment:
card:
type: custom:button-card
show_name: true
show_icon: false
show_state: false
name: |
[[[
const temp = Number(entity.state);
if (isNaN(temp)) return "Indisponible";
if (temp < 14) return "En dehors de l'échelle";
if (temp >= 14 && temp < 16) return "Froid";
if (temp >= 16 && temp < 18.5) return "Frais";
if (temp >= 18.5 && temp <= 22) return "Confortable";
if (temp > 22 && temp <= 24) return "Tiède";
if (temp > 24 && temp < 27) return "Chaud";
if (temp >= 27 && temp <= 30) return "Canicule";
if (temp > 30) return "En dehors de l'échelle";
return "Indisponible";
]]]
styles:
card:
- height: 25px
- width: auto
- border-radius: 999px
- border: 0
- padding: 8px
- background: white
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},0.5)`;
]]]
name:
- font-size: 0.9rem
- font-weight: 600
- color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
styles:
card:
- background-color: rgba(42,45,54,1.0)
- aspect-ratio: 7/1
- cursor: default
custom_fields:
icon:
- position: absolute
- top: 37%
- left: 1%
name:
- position: absolute
- top: 3%
- left: 8%
separation:
- position: absolute
- top: 17%
- left: 0%
value:
- position: absolute
- top: 0%
- right: 6.5%
- margin-top: -0.5%
unit:
- position: absolute
- right: 2%
- top: 1%
- margin-left: 1%
min_val:
- position: absolute
- bottom: 2%
- left: 38%
max_val:
- position: absolute
- bottom: 2%
- right: 4%
comment:
- position: absolute
- left: 17%
- top: 55%
- transform: translate(-50%, -50%)
bar:
- position: absolute
- right: 7%
- top: 55%
- transform: translateY(-50%)
cursor:
- position: absolute
- top: "[[[ return 'calc(55% - 12.5px)'; ]]]"
- left: |
[[[
const value = Number(entity.state);
const min = 14;
const max = 30;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const t = clamp(value, min, max);
const percent = (t - min) * 6.25;
const barWidth = 250;
const halfCursor = 8;
const barRightPercent = 7;
const offsetPx = (barWidth * percent) / 100;
return `calc(100% - ${barRightPercent}% - ${barWidth}px + ${offsetPx}px - ${halfCursor}px)`;
]]]
J’ai un décalage de barre et c’est rigolo, l’icône est devenue plus grosse, je t’ai mis celle avec mon code précédent au dessus pour voir, mais je regarde ton code et je crois comprendre, je vais essayer de me l’appliquer
J’ai travaillé sur l’image postée plus haut (probablement depuis ton PC) du coup ça ne colle plus sur téléphone portable. J’ai grossi l’icône pour qu’elle ait la même hauteur que « comment », j’ai réduit la taille de police de « value » et « unit » pour que le curseur n’en efface pas une partie quand la température est elevée.
Voilà le rendu sur PC (j’ai ajouté par rapport au code que je t’ai mis plus haut le déplacement dynamique de « comment » pour qu’il soit centré entre « icon » et « bar ») :

Ah ok, moi en effet je regarde sur mon portable, ça marche, je vais adapter ![]()
Je vais te faire une version responsive qui adaptera l’affichage en fonction de la largeur de l’écran sur lequel est affichée la carte
Voici ce que je viens de faire à partir de ton code que j’aime bien.
Ça ne me dérange pas que le curseur passe en dessous sur la fin, c’est pour ça que j’avais réorganisé la position des éléments dans ton code de départ en comprenant l’ordre de superposition
type: custom:button-card
entity: input_number.test
show_state: false
show_icon: false
show_name: false
tap_action: none
double_tap_action: none
hold_action: none
custom_fields:
icon:
card:
type: custom:button-card
icon: mdi:thermometer
styles:
card:
- aspect-ratio: 1/1
- width: 20px
- padding: 0
- border: 1px solid white
- border-radius: 50%
- background: none
icon:
- width: 90%
- color: white
name:
card:
type: custom:button-card
name: Netatmo Salon Température
styles:
card:
- width: 300px
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1rem
- align-self: start
- justify-self: start
- color: white
- font-weight: 500
separation:
card:
type: custom:button-card
styles:
card:
- width: 600px
- height: 0px
- padding: 0
- border: 0px solid transparent
- border-radius: 0
- background: none
bar:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- height: 6px
- width: 250px
- border-radius: 999px
- border: 0
- padding: 0
- background: |-
linear-gradient(to right,
rgba(255,0,0,1.0) 0%, /* 14°C rouge */
rgba(255,255,0,1.0) 12.5%, /* 16°C jaune */
rgba(200,255,120,1.0) 21.875%, /* 17.5°C jaune-vert */
rgba(0,255,0,1.0) 28.125%, /* 18.5°C début vert */
rgba(0,255,0,1.0) 50%, /* 22°C vert saturé */
rgba(180,255,100,1.0) 56.25%, /* 23°C vert-jaune */
rgba(255,255,0,1.0) 62.5%, /* 24°C jaune */
rgba(255,210,0,1.0) 68.75%, /* 25°C jaune-orangé */
rgba(255,120,0,1.0) 75%, /* 26°C orange-rouge (début rouge) */
rgba(255,60,0,1.0) 87.5%, /* 28°C rouge vif */
rgba(255,0,0,1.0) 100%) /* 30°C rouge saturé */
cursor:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- width: 12px
- height: 25px
- border-radius: 999px
- border: 4px solid rgba(42,45,54,1.0)
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state) || minTemp;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] }, // 14
{ p: 12.5, c: [255, 255, 0] }, // 16
{ p: 21.875, c: [200, 255, 120] }, // 17.5
{ p: 28.125, c: [0, 255, 0] }, // 18.5
{ p: 50, c: [0, 255, 0] }, // 22
{ p: 56.25, c: [180, 255, 100] }, // 23
{ p: 62.5, c: [255, 255, 0] }, // 24
{ p: 68.75, c: [255, 210, 0] }, // 25 (jaune-orangé)
{ p: 75, c: [255, 120, 0] }, // 26 (orange-rouge)
{ p: 87.5, c: [255, 60, 0] }, // 28 (rouge vif)
{ p: 100, c: [255, 0, 0] } // 30 (rouge saturé)
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
value:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: true
state_display: |
[[[
const v = Number(entity.state);
if (isNaN(v)) return '—';
return v.toFixed(1);
]]]
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
state:
- color: white
- font-size: 2rem
- font-weight: 700
unit:
card:
type: custom:button-card
name: °C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.4rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 800
min_val:
card:
type: custom:button-card
name: 14°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.0rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
max_val:
card:
type: custom:button-card
name: 30°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: 1.0rem
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
comment:
card:
type: custom:button-card
show_name: true
show_icon: false
show_state: false
name: |
[[[
const temp = Number(entity.state);
if (isNaN(temp)) return "Indisponible";
if (temp < 14) { return "En dehors de l'échelle"; }
if (temp >= 14 && temp <= 15) { return "Froid"; }
if (temp >= 16 && temp < 18.5) { return "Frais"; }
if (temp >= 18.5 && temp <= 22) { return "Confortable"; }
if (temp > 22 && temp <= 24) { return "Tiède"; }
if (temp > 24 && temp < 27) { return "Chaud"; }
if (temp >= 27) { return "Canicule"; }
return "Indisponible";
]]]
styles:
card:
- height: 8px
- width: auto
- border-radius: 999px
- border: 0
- padding: 8px
- background: white
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5, c: [255, 255, 0] },
{ p: 21.875, c: [200, 255, 120] },
{ p: 28.125, c: [0, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 56.25, c: [180, 255, 100] },
{ p: 62.5, c: [255, 255, 0] },
{ p: 68.75, c: [255, 210, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 87.5, c: [255, 60, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},0.5)`;
]]]
name:
- font-size: 0.9rem
- font-weight: 600
- color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5, c: [255, 255, 0] },
{ p: 21.875, c: [200, 255, 120] },
{ p: 28.125, c: [0, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 56.25, c: [180, 255, 100] },
{ p: 62.5, c: [255, 255, 0] },
{ p: 68.75, c: [255, 210, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 87.5, c: [255, 60, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
styles:
card:
- background-color: rgba(42,45,54,1.0)
- aspect-ratio: 7/1
- cursor: default
custom_fields:
icon:
- position: absolute
- top: 30%
- left: 1%
name:
- position: absolute
- top: 3%
- left: 8%
separation:
- position: absolute
- top: 17%
- left: 0%
value:
- position: absolute
- top: 26%
- right: 6.5%
- margin-right: 1%
- transform: translateY(-50%)
unit:
- position: absolute
- left: 92%
- top: 20%
- margin-left: 1%
- transform: translateY(-50%)
min_val:
- position: absolute
- top: 65%
- left: 28%
max_val:
- position: absolute
- top: 65%
- right: 1%
comment:
- position: absolute
- left: 17%
- top: 65%
- transform: translate(-50%, -50%)
bar:
- position: absolute
- right: 3.5%
- top: 55%
- transform: translateY(-50%)
cursor:
- position: absolute
- top: "[[[ return 'calc(55% - 12.5px)'; ]]]"
- left: |
[[[
const value = Number(entity.state);
const min = 14;
const max = 30;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const t = clamp(value, min, max);
const percent = (t - min) * 6.25;
const barWidth = 250;
const halfCursor = 8;
const barRightPercent = 3.5;
const offsetPx = (barWidth * percent) / 100;
return `calc(100% - ${barRightPercent}% - ${barWidth}px + ${offsetPx}px - ${halfCursor}px)`;
]]]
Voici tout en bas l’aperçu du code ci-dessus sur mon téléphone
J’avais aligné verticalement l’icône, le « comment » et la barre.
Voici ce que ça donne sur PC avec le « comment » centré entre l’icône et la barre :


Je te fais une version responsive (cet affichage sur PC) et l’affichage retravaillé sur téléphone portable. Je t’envoie le code dans la matinée.
Impressionnant, merci, je regarderai dans la journée ou ce soir
Affichage PC :




Affichage téléphone portable :
Le code :
type: custom:button-card
entity: input_number.test_temp
show_state: false
show_icon: false
show_name: false
tap_action: none
double_tap_action: none
hold_action: none
custom_fields:
icon:
card:
type: custom:button-card
icon: mdi:thermometer
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '20px' : '25px' ]]]"
- border: none
- border-radius: 50%
- background: none
icon:
- width: "[[[ return window.innerWidth <= 600 ? '18px' : '20px' ]]]"
- color: white
icon_border:
card:
type: custom:button-card
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '23px' : '25px' ]]]"
- border: 1px solid white
- border-radius: 50%
- background: none
name:
card:
type: custom:button-card
name: Netatmo Salon Température
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.9rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: white
- font-weight: 500
bar:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- height: 6px
- width: |
[[[ return window.innerWidth <= 600 ? "220px" : "250px"; ]]]
- border-radius: 999px
- border: 0
- padding: 0
- background: |-
linear-gradient(to right,
rgba(255,0,0,1.0) 0%,
rgba(255,255,0,1.0) 12.5%,
rgba(0,255,0,1.0) 50%,
rgba(255,255,0,1.0) 62.5%,
rgba(255,120,0,1.0) 75%,
rgba(255,0,0,1.0) 100%)
cursor:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- width: 12px
- height: 25px
- border-radius: 999px
- border: 4px solid rgba(42,45,54,1.0)
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state) || minTemp;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
value:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: true
state_display: |
[[[
const v = Number(entity.state);
return isNaN(v) ? '—' : v.toFixed(1);
]]]
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
state:
- color: white
- font-size: "[[[ return window.innerWidth <= 600 ? '1.6rem' : '1.8rem' ]]]"
- font-weight: 700
unit:
card:
type: custom:button-card
name: °C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '1.1rem' : '1.3rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 800
min_val:
card:
type: custom:button-card
name: 14°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
max_val:
card:
type: custom:button-card
name: 30°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
comment:
card:
type: custom:button-card
show_name: true
show_icon: false
show_state: false
name: |
[[[
const temp = Number(entity.state);
if (isNaN(temp)) return "Indisponible";
if (temp < 14) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
if (temp >= 14 && temp < 16) return "Froid";
if (temp >= 16 && temp < 18.5) return "Frais";
if (temp >= 18.5 && temp <= 22) return "Confortable";
if (temp > 22 && temp <= 24) return "Tiède";
if (temp > 24 && temp < 27) return "Chaud";
if (temp >= 27 && temp <= 30) return "Canicule";
if (temp > 30) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
return "Indisponible";
]]]
styles:
card:
- height: 25px
- width: auto
- border-radius: 999px
- border: none
- padding: 0px 8px 0px 8px
- background: white
- background-color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},0.5)`;
]]]
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '0.9rem' ]]]"
- font-weight: 600
- line-height: |
[[[
return window.innerWidth <= 600 ? "0.9" : "normal";
]]]
- color: |
[[[
const minTemp = 14;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
styles:
card:
- background-color: rgba(42,45,54,1.0)
- aspect-ratio: 7/1
- cursor: default
custom_fields:
icon:
- position: absolute
- top: 55%
- left: 4%
- transform: translate(-50%, -50%)
icon_border:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '56%' : '55%' ]]]"
- left: 4%
- transform: translate(-50%, -50%)
name:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '1%' : '3%' ]]]"
- left: 8%
value:
- position: absolute
- top: 0%
- right: 6.5%
- margin-top: "-0.5%"
unit:
- position: absolute
- right: 2%
- top: 1%
- margin-left: 1%
min_val:
- position: absolute
- bottom: 2%
- left: "[[[ return window.innerWidth <= 600 ? '34%' : '38%' ]]]"
max_val:
- position: absolute
- bottom: 2%
- right: "[[[ return window.innerWidth <= 600 ? '2%' : '4%' ]]]"
comment:
- position: absolute
- top: 55%
- left: |
[[[
const iconLeftPercent = 1;
const iconDiameterPx = window.innerWidth <= 600 ? 20 : 25;
const barWidthPx = window.innerWidth <= 600 ? 220 : 250;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const iconRightExpr = `calc(${iconLeftPercent}% + ${iconDiameterPx}px)`;
const barLeftExpr = `calc(100% - ${barRightPercent}% - ${barWidthPx}px)`;
return `calc( ( ${iconRightExpr} + ${barLeftExpr} ) / 2 )`;
]]]
- transform: translate(-50%, -50%)
bar:
- position: absolute
- right: "[[[ return window.innerWidth <= 600 ? '4%' : '7%' ]]]"
- top: 55%
- transform: translateY(-50%)
cursor:
- position: absolute
- top: "[[[ return 'calc(55% - 12.5px)'; ]]]"
- left: |
[[[
const value = Number(entity.state);
const min = 14;
const max = 30;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const t = clamp(value, min, max);
const barWidth = window.innerWidth <= 600 ? 220 : 250;
const halfCursor = 8;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const percent = (t - min) * 6.25;
const offsetPx = (barWidth * percent) / 100;
return `calc(100% - ${barRightPercent}% - ${barWidth}px + ${offsetPx}px - ${halfCursor}px)`;
]]]
Bonjour,
J’ai adapté la fourchette de température, j’ai remplacé tous les 14 dans le code par 0

Le curseur ne se positionne pas correctement, j’ai joué sur halfCursor sans succès.
Merci d’avance.
Bob
Salut @Bob,
Postes moi ton code. Ce n’est pas sur halfCursor qu’il faut jouer, halfCursor permet juste de retrancher la moitié de la largeur du curseur pour mieux le postionner.
Le voici @btncrd
type: custom:button-card
entity: sensor.temperature_ext
show_state: false
show_icon: false
show_name: false
tap_action: none
double_tap_action: none
hold_action: none
custom_fields:
icon:
card:
type: custom:button-card
icon: mdi:thermometer
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '20px' : '25px' ]]]"
- border: none
- border-radius: 50%
- background: none
icon:
- width: "[[[ return window.innerWidth <= 600 ? '18px' : '20px' ]]]"
- color: white
icon_border:
card:
type: custom:button-card
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '23px' : '25px' ]]]"
- border: 1px solid white
- border-radius: 50%
- background: none
name:
card:
type: custom:button-card
name: Température Extérieur
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.9rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: white
- font-weight: 500
bar:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- height: 6px
- width: |
[[[ return window.innerWidth <= 600 ? "220px" : "250px"; ]]]
- border-radius: 999px
- border: 0
- padding: 0
- background: |-
linear-gradient(to right,
rgba(255,0,0,1.0) 0%,
rgba(255,255,0,1.0) 12.5%,
rgba(0,255,0,1.0) 50%,
rgba(255,255,0,1.0) 62.5%,
rgba(255,120,0,1.0) 75%,
rgba(255,0,0,1.0) 100%)
cursor:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- width: 12px
- height: 25px
- border-radius: 999px
- border: 4px solid rgba(42,45,54,1.0)
- background-color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state) || minTemp;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
value:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: true
state_display: |
[[[
const v = Number(entity.state);
return isNaN(v) ? '—' : v.toFixed(1);
]]]
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
state:
- color: white
- font-size: "[[[ return window.innerWidth <= 600 ? '1.6rem' : '1.8rem' ]]]"
- font-weight: 700
unit:
card:
type: custom:button-card
name: °C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '1.1rem' : '1.3rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 800
min_val:
card:
type: custom:button-card
name: 0°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
max_val:
card:
type: custom:button-card
name: 30°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
comment:
card:
type: custom:button-card
show_name: true
show_icon: false
show_state: false
name: |
[[[
const temp = Number(entity.state);
if (isNaN(temp)) return "Indisponible";
if (temp < 0) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
if (temp >= 0 && temp < 16) return "Froid";
if (temp >= 16 && temp < 18.5) return "Frais";
if (temp >= 18.5 && temp <= 22) return "Confortable";
if (temp > 22 && temp <= 24) return "Tiède";
if (temp > 24 && temp < 27) return "Chaud";
if (temp >= 27 && temp <= 30) return "Canicule";
if (temp > 30) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
return "Indisponible";
]]]
styles:
card:
- height: 25px
- width: auto
- border-radius: 999px
- border: none
- padding: 0px 8px 0px 8px
- background: white
- background-color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},0.5)`;
]]]
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '0.9rem' ]]]"
- font-weight: 600
- line-height: |
[[[
return window.innerWidth <= 600 ? "0.9" : "normal";
]]]
- color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
styles:
card:
- background-color: rgba(42,45,54,1.0)
- aspect-ratio: 7/1
- cursor: default
custom_fields:
icon:
- position: absolute
- top: 55%
- left: 4%
- transform: translate(-50%, -50%)
icon_border:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '56%' : '55%' ]]]"
- left: 4%
- transform: translate(-50%, -50%)
name:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '1%' : '3%' ]]]"
- left: 8%
value:
- position: absolute
- top: 0%
- right: 6.5%
- margin-top: "-0.5%"
unit:
- position: absolute
- right: 2%
- top: 1%
- margin-left: 1%
min_val:
- position: absolute
- bottom: 2%
- left: "[[[ return window.innerWidth <= 600 ? '34%' : '38%' ]]]"
max_val:
- position: absolute
- bottom: 2%
- right: "[[[ return window.innerWidth <= 600 ? '2%' : '4%' ]]]"
comment:
- position: absolute
- top: 55%
- left: |
[[[
const iconLeftPercent = 1;
const iconDiameterPx = window.innerWidth <= 600 ? 20 : 25;
const barWidthPx = window.innerWidth <= 600 ? 220 : 250;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const iconRightExpr = `calc(${iconLeftPercent}% + ${iconDiameterPx}px)`;
const barLeftExpr = `calc(100% - ${barRightPercent}% - ${barWidthPx}px)`;
return `calc( ( ${iconRightExpr} + ${barLeftExpr} ) / 2 )`;
]]]
- transform: translate(-50%, -50%)
bar:
- position: absolute
- right: "[[[ return window.innerWidth <= 600 ? '4%' : '7%' ]]]"
- top: 55%
- transform: translateY(-50%)
cursor:
- position: absolute
- top: "[[[ return 'calc(55% - 12.5px)'; ]]]"
- left: |
[[[
const value = Number(entity.state);
const min = 0;
const max = 30;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const t = clamp(value, min, max);
const barWidth = window.innerWidth <= 600 ? 220 : 250;
const halfCursor = 8;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const percent = (t - min) * 6.25;
const offsetPx = (barWidth * percent) / 100;
return `calc(100% - ${barRightPercent}% - ${barWidth}px + ${offsetPx}px - ${halfCursor}px)`;
]]]
Bob
Teste avec ce code :
type: custom:button-card
entity: input_number.test_temp
show_state: false
show_icon: false
show_name: false
tap_action: none
double_tap_action: none
hold_action: none
custom_fields:
icon:
card:
type: custom:button-card
icon: mdi:thermometer
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '20px' : '25px' ]]]"
- border: none
- border-radius: 50%
- background: none
icon:
- width: "[[[ return window.innerWidth <= 600 ? '18px' : '20px' ]]]"
- color: white
icon_border:
card:
type: custom:button-card
styles:
card:
- aspect-ratio: 1/1
- width: "[[[ return window.innerWidth <= 600 ? '23px' : '25px' ]]]"
- border: 1px solid white
- border-radius: 50%
- background: none
name:
card:
type: custom:button-card
name: Netatmo Salon Température
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.9rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: white
- font-weight: 500
bar:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- height: 6px
- width: |
[[[ return window.innerWidth <= 600 ? "220px" : "250px"; ]]]
- border-radius: 999px
- border: 0
- padding: 0
- background: |-
linear-gradient(to right,
rgba(255,0,0,1.0) 0%,
rgba(255,255,0,1.0) 12.5%,
rgba(0,255,0,1.0) 50%,
rgba(255,255,0,1.0) 62.5%,
rgba(255,120,0,1.0) 75%,
rgba(255,0,0,1.0) 100%)
cursor:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: false
styles:
card:
- width: 12px
- height: 25px
- border-radius: 999px
- border: 4px solid rgba(42,45,54,1.0)
- background-color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state) || minTemp;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
value:
card:
type: custom:button-card
show_name: false
show_icon: false
show_state: true
state_display: |
[[[
const v = Number(entity.state);
return isNaN(v) ? '—' : v.toFixed(1);
]]]
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
state:
- color: white
- font-size: "[[[ return window.innerWidth <= 600 ? '1.6rem' : '1.8rem' ]]]"
- font-weight: 700
unit:
card:
type: custom:button-card
name: °C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '1.1rem' : '1.3rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 800
min_val:
card:
type: custom:button-card
name: 0°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
max_val:
card:
type: custom:button-card
name: 30°C
styles:
card:
- width: auto
- padding: 0
- border: none
- border-radius: 0
- background: none
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '1.0rem' ]]]"
- align-self: start
- justify-self: start
- color: rgba(167,176,205,1.0)
- font-weight: 400
comment:
card:
type: custom:button-card
show_name: true
show_icon: false
show_state: false
name: |
[[[
const temp = Number(entity.state);
if (isNaN(temp)) return "Indisponible";
if (temp < 0) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
if (temp >= 0 && temp < 7) return "Glacial";
if (temp >= 7 && temp < 14) return "Très froid";
if (temp >= 14 && temp < 16) return "Froid";
if (temp >= 16 && temp < 18.5) return "Frais";
if (temp >= 18.5 && temp <= 22) return "Confortable";
if (temp > 22 && temp <= 24) return "Tiède";
if (temp > 24 && temp < 27) return "Chaud";
if (temp >= 27 && temp <= 30) return "Canicule";
if (temp > 30) {
return window.innerWidth <= 600 ? "En dehors<br>de l'échelle" : "En dehors de l'échelle";
}
return "Indisponible";
]]]
styles:
card:
- height: 25px
- width: auto
- border-radius: 999px
- border: none
- padding: 0px 8px 0px 8px
- background: white
- background-color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},0.5)`;
]]]
name:
- font-size: "[[[ return window.innerWidth <= 600 ? '0.8rem' : '0.9rem' ]]]"
- font-weight: 600
- line-height: |
[[[
return window.innerWidth <= 600 ? "0.9" : "normal";
]]]
- color: |
[[[
const minTemp = 0;
const maxTemp = 30;
const temp = Number(entity.state);
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const percent = isNaN(temp) ? 0 : clamp(((temp - minTemp) / (maxTemp - minTemp)) * 100, 0, 100);
const stops = [
{ p: 0, c: [255, 0, 0] },
{ p: 12.5,c: [255, 255, 0] },
{ p: 50, c: [0, 255, 0] },
{ p: 62.5,c: [255, 255, 0] },
{ p: 75, c: [255, 120, 0] },
{ p: 100, c: [255, 0, 0] }
];
let i = 1;
while (i < stops.length && percent > stops[i].p) i++;
const a = stops[i - 1], b = stops[i];
const t = (percent - a.p) / (b.p - a.p);
const lerp = (x, y, t) => Math.round(x + (y - x) * t);
const r = lerp(a.c[0], b.c[0], t);
const g = lerp(a.c[1], b.c[1], t);
const bcol = lerp(a.c[2], b.c[2], t);
return `rgba(${r},${g},${bcol},1.0)`;
]]]
styles:
card:
- background-color: rgba(42,45,54,1.0)
- aspect-ratio: 7/1
- cursor: default
custom_fields:
icon:
- position: absolute
- top: 55%
- left: 4%
- transform: translate(-50%, -50%)
icon_border:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '56%' : '55%' ]]]"
- left: 4%
- transform: translate(-50%, -50%)
name:
- position: absolute
- top: "[[[ return window.innerWidth <= 600 ? '1%' : '3%' ]]]"
- left: 8%
value:
- position: absolute
- top: 0%
- right: 6.5%
- margin-top: "-0.5%"
unit:
- position: absolute
- right: 2%
- top: 1%
- margin-left: 1%
min_val:
- position: absolute
- bottom: 2%
- left: "[[[ return window.innerWidth <= 600 ? '34%' : '38%' ]]]"
max_val:
- position: absolute
- bottom: 2%
- right: "[[[ return window.innerWidth <= 600 ? '2%' : '4%' ]]]"
comment:
- position: absolute
- top: 55%
- left: |
[[[
const iconLeftPercent = 1;
const iconDiameterPx = window.innerWidth <= 600 ? 20 : 25;
const barWidthPx = window.innerWidth <= 600 ? 220 : 250;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const iconRightExpr = `calc(${iconLeftPercent}% + ${iconDiameterPx}px)`;
const barLeftExpr = `calc(100% - ${barRightPercent}% - ${barWidthPx}px)`;
return `calc( ( ${iconRightExpr} + ${barLeftExpr} ) / 2 )`;
]]]
- transform: translate(-50%, -50%)
bar:
- position: absolute
- right: "[[[ return window.innerWidth <= 600 ? '4%' : '7%' ]]]"
- top: 55%
- transform: translateY(-50%)
cursor:
- position: absolute
- top: "[[[ return 'calc(55% - 12.5px)'; ]]]"
- left: |
[[[
const value = Number(entity.state);
const min = 0;
const max = 30;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
const t = clamp(value, min, max);
const barWidth = window.innerWidth <= 600 ? 220 : 250;
const halfCursor = 8;
const barRightPercent = window.innerWidth <= 600 ? 4 : 7;
const percent = ((t - min) / (max - min)) * 100;
const offsetPx = (barWidth * percent) / 100;
return `calc(100% - ${barRightPercent}% - ${barWidth}px + ${offsetPx}px - ${halfCursor}px)`;
]]]
Il fallait prendre en compte que le delta de température est passé de 16°C (30° - 14°) à 30°C et donc chaque degré ne représente plus 6.25% de la longueur de la barre. Il faudra ajuster les pourcentages pour le dégradé linéaire car du coup « Confortable » est en orange.
Ok, nickel, merci @btncrd
Bob
J’ai intégré ton code, c’est vrai que c’est sympa même si j’aurais aimé la barre un poil plus longue mais franchement je chipote.
Mais du coup pour l’humidité etc… On ne peut pas reprendre directement le code, il y a des variations importantes pour chaque capteur non?
Le responsive forcément c’est top
J’ai mis en comparaison les avants après
Le boulot que tu as fait est vraiment incroyable, je t’en remercie vraiment, ça fait vraiment plaisir
lol, tu as une sacrée base pour ta carte. Maintenant, il faut apprendre à utiliser button-card. @btncrd va pas tout te faire ![]()
C’est pas ainsi que tu vas apprendre.
La longueur de la barre est liée à la longueur des commentaires et notamment celui-là :

Mais il est possible de gagner quelques pixels en longueur en diminuant l’espace à droite et quelques pixels en augmentant légèrement la longueur tout en gardant suffisamment d’espace entre la barre et l’icône pour afficher tous les commentaires possibles.
Pour les autres cartes, la base reste la même (CO2 : delta de 1600 à la place du delta de 16 pour la température, Humidité : delta de 100, etc.).
Il faut à côté de cela jouer avec les pourcentages des dégradés pour être cohérent avec la logique d’affichage.
Copilot te corrigera le code sans souci avec le bon prompt maintenant que tu as la base.
Oui, oui c’est clair c’est pour ça que je tente des choses, c’est génial d’essayer de comprendre quelle partie fait quoi
Super je vais pouvoir regarder ça, je pensais qu’il y avait beaucoup plus de paramètres dans le code à modifier. Merci c’est top.
Dès que j’aurais cumulé mes capteurs je vous montre ça ![]()
![]()
![]()







