Bonjour,
Je sais qu’il existe deja une carte horizon card mais je l’a trouvé trop grosse et sur mon tableau de bord je voulais quelque chose d’assez discret.
Les calculs sont fait à l’aide d’IA. Il n’y a aucune prétention et je partage car si quelqu’un veut améliorer s’est sans soucis. C’est fait base buttom-card et card-mod, il faut aussi l’intégration lune car en fin de journée a la place du soleil apparait la lune avec son quartier ou pleine.
Image :
Code :
type: custom:button-card
entity: sun.sun
show_name: false
show_icon: false
styles:
card:
- height: 160px
- padding: 10px
- border-radius: 15px
grid:
- grid-template-areas: |
"arc"
"heures"
- grid-template-rows: 95px 45px
custom_fields:
arc: |
[[[
const az = states['sun.sun'].attributes.azimuth;
const el = states['sun.sun'].attributes.elevation;
const moon = states['sensor.moon'] ? states['sensor.moon'].state : 'full_moon';
const x = ((az - 90) / 180) * 240 + 30;
const t = (x - 30) / 240;
const y = (1 - t) * (1 - t) * 85 + 2 * (1 - t) * t * -10 + t * t * 85;
const isDay = el > 0;
let visual = "";
let color = "#FFCE20";
if (isDay) {
const ratio = Math.min(Math.max(el / 40, 0), 1);
const g = Math.round(130 + (125 * ratio));
const b = Math.round(0 + (120 * ratio));
color = `rgb(255, ${g}, ${b})`;
visual = `<circle cx="${x}" cy="${y}" r="7" fill="${color}" style="transition: all 1s; filter: drop-shadow(0 0 10px ${color});" />`;
} else {
const phases = {'new_moon': 0.1, 'waxing_crescent': 0.3, 'first_quarter': 0.5, 'waxing_gibbous': 0.8, 'full_moon': 1, 'waning_gibbous': 0.8, 'last_quarter': 0.5, 'waning_crescent': 0.3};
let p = phases[moon] ?? 1;
const r = 10;
const s = p > 0.5 ? 0 : 1;
const iR = Math.max(Math.abs(p - 0.5) * 2.2 * r, 0.5);
visual = `<g transform="translate(${x}, ${y})"><circle r="${r}" fill="#1a1a1a" stroke="rgba(93, 169, 221, 0.2)" stroke-width="0.5" /><path d="M 0 ${-r} A ${r} ${r} 0 1 ${s} 0 ${r} A ${iR} ${r} 0 1 ${1-s} 0 ${-r}" fill="#5da9dd" style="filter: drop-shadow(0 0 8px #3a7bd5);" /></g>`;
}
const hColor = isDay ? color.replace('rgb', 'rgba').replace(')', ', 0.15)') : 'rgba(58, 123, 213, 0.15)';
return `<svg viewBox="0 0 300 100" style="width:100%; height:100%; overflow: visible;"><defs><radialGradient id="h" cx="${x/3}%" cy="${y}%" r="60%"><stop offset="0%" stop-color="${hColor}" /><stop offset="100%" stop-color="transparent" /></radialGradient></defs><rect width="300" height="100" fill="url(#h)" style="transition: all 1s;" /><path d="M 30 85 Q 150 -10 270 85" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="2" stroke-dasharray="4,4" />${visual}<line x1="20" y1="86" x2="280" y2="86" stroke="rgba(255,255,255,0.05)" stroke-width="1" /></svg>`;
]]]
heures: |
[[[
const r = new Date(states['sun.sun'].attributes.next_rising).toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'});
const s = new Date(states['sun.sun'].attributes.next_setting).toLocaleTimeString('fr-FR', {hour: '2-digit', minute: '2-digit'});
return `<div style="display: flex; justify-content: space-between; width: 90%; margin: 5px auto 0;"><div style="text-align: center;"><div style="color: rgba(255,255,255,0.2); font-size: 8px; font-weight: bold;">LEVER</div><span style="color: #FFA726; font-size: 14px; font-weight: 900;">${r}</span></div><div style="text-align: center;"><div style="color: rgba(255,255,255,0.2); font-size: 8px; font-weight: bold;">COUCHER</div><span style="color: #F44336; font-size: 14px; font-weight: 900;">${s}</span></div></div>`;
]]]
Merci











