Salut @Matt1,
J’ai trouvé que ton besoin était relativement simple à faire et donc, plutôt que de te poster du code tout fait, j’allais te montrer comment arriver au résultat voulu sous forme de didacticiel (cela pourra éventuellement servir à d’autre).
A la base, tu voudrais modifier une carte que je t’avais faite, basée sur une custom:button-card en ajoutant deux boutons à la gauche de la carte existente. Cette carte comprenait trois zones, une zone « Portail & Garage », une zone « Portail » avec indication de l’état du portail (ouvert/fermé) et une zone « Garage » avec là aussi indication de l’état. Cette carte n’utilise pas horizontal-stack mais des custom_fields. On partira donc sur une carte custom:button-card avec 5 zones découpées selon ce shéma :
Nous pourrions le faire avec vertical-stack et horizontal-stack mais nous allons nous servir uniquement de custom:button-card et de custom_fields (un custom_fields par zone). Nous partirons sur un affichage pour écran d’ordinateur en mode payasage (ou une tablette), dans cette configuration, Home Assistant propose automatiquement une disposition des cartes sur trois colonnes. Nous aurons donc une carte « support » de la largeur d’une colonne et nous jouerons simplement sur la hauteur de cette carte pour qu’elle soit aussi fine que possible, au départ nous définirons un ratio de 4/1 (soit une carte 4 fois plus longue que haute)
Nous allons ensuite définer les propriétés de la carte « support », c’est à dire la couleur de fond, la couleur de bordure et son épaisseur, le rayon de l’arrondi, l’ombrage, le relief, etc.
Ces propriétés visuelles se définissent avec « styles » et s’appliquent pour chaque éléments de la carte (la carte elle-même, l’icone, le nom, l’étiquette, etc.). Ici nous modifions uniquement les propriétés de la carte…
Si nous voulons donner un effet de relief à la carte, nous supprimer la propriété : border-width: 2px" et la remplacer par « border: 2px rgba(211,211,211,1.0) outset » :
Pour obtenir une carte représentant un bouton rond en relief (surélevé) il faudra simplement définir l’aspect_ratio à 1/1 et le border-radius à 50% :
Mais nous aurions alors un bouton énorme. Nous reviendrons à ces options pour les boutons des zones 1 et 2.
Pour notre carte « support » nous allons revenir aux propriétés suivantes :
Nous pourrions ajouter à cette carte un nom, une étiquette (label), une icône ou une image personnalisée, etc. et définir les styles pour chacun de ces éléments mais nous y reviendrons plus tard.
Nous allons plutôt nous intéresser maintenant aux custom_fields. Un custom_fields est, comme son nom l’indique, un champ personnalisé pouvant contenir n’importe quelle carte et se positionner où bon nous semble sur la carte « support ». Ici , nous utiliserons des custom_fields contenant tous des custom:button-cards.
Pour ajouter des custom_fields, il faut d’abord définir cet élément :
Ensuite, il faudra donner un nom à chacun des custom_fields et définir quel type de carte il contient :
Sans autres précisions, le custom_fields ainsi créé correspond au petit point gris en bas à gauche de la carte « support ».
Le positionnement du custom_fields sur la carte « support » se défini dans les styles de celle-ci. Pour une meilleure lisibilité, nous allons donc déplacer les styles de la carte « support » tout en bas dans le code. Pour le moment, nous allons mettre le point de ce custom_fields à peu près à son emplacement définitif (grace à « position: absolute » et son positionnement par rapport au bord gauche et au bord haut de la carte « support ») :
Nous allons maintenir définir les propriétés de ce custom_fields (bouton rond en relief avec une icône grise de cadenas fermé dans un bouclier :
Si vous copiez le code tel quel dans un tableau de bord, vous pourrez constater qu’en cliquant sur le custom_fields, il n’y aura pas d’effet visuel alors qu’en cliquant n’importe où sur la carte « support », l’effet visuel lié au clic sera visible. Pour que l’effet visuel lié au clic soit visible sur le custom_fields, il faudra remplacer « action: none » par l’appel à un script par exemple mais ce qui fonctionne avec le custom_fields ne marche pas avec la carte « support ». Pour supprimer cet effet visuel sur le clic sur la carte support, il faudra ajouter une propriété particulière dans les styles de la carte « support » :
- "--mdc-ripple-press-opacity": 0
(merci à @WarC0zes pour cette astuce) et - "--mdc-ripple-press-opacity": 0.12
dans les styles de la carte des custom_fields…Le positionnement des custom_fields peut être donné en pourcentage (de la largeur et de la hauteur de la carte « support ») ou en pixels. Le pourcentage sera proportionnel à la taille de cette carte et le positionnement restera plus ou moins identique en fonction des variations liées à l’affichage alors que le positionnement en pixels ne changera pas. Ainsi des custom_fields pourraient se superposer dans le cas d’un positionnement en pixels.
Dans les exemples précédants, nous avions défini la couleur de fond en rgba (red, green, blue, alpha) avec une valeur de 32 pour chacune des composantes « couleur » (chaque valeur devant être comprise entre 0 et 255) et une valeur de 0.9 pour la composante « alpha ». Cette composante permet de définir la transparence de la couleur (0.0 : couleur totalement transparente à 1.0 : couleur parfaitement opaque). Pour que la couleur de fond du custom_fields soit parfaitement égale à celle de la carte « support », nous allons redéfinir ces couleurs avec les mêmes valeurs en supprimant la légère transparence. Nous allons donc changer
rgba(32, 32, 32, 0.9)
par rgba(54, 54, 54, 1.0)
pour la couleur de fond de la carte « support » et la couleur de fond du custom_fields. Nous allons par ailleurs revenir à une bordure d’un pixel d’épaisseur et définir la couleur de la bordure ainsi : rgba(211,211,211,0.5)
pour coller au visuel de @Matt1.Nous allons maintenant définir la couleur de l’icône en fonction de l’état de l’alarme. Pour vérifier le bon fonctionnement, je vais créer une entrée « Liste déroulante » avec trois valeurs possibles (« disarmed », « armed_away » et « arming »).
Pour ce faire, nous allons simplement modifier le paramètre « color » de l’élément « icon » en fonction de l’état de notre entrée « Liste déroulante » que j’ai nommé « list_alarm » et de gérer le clignotement de l’icône si l’entrée est sur « arming ».
Pour l’animation, nous allons un paramètre « animation » dans l’élément « icon ». Nous pourrions de la même manière faire clignoter le custom_fields en mettant ce paramètre dans l’élément « card » du custom_fields « zone_1 ».
Il suffira pour @Matt1 de remplacer l’appel à l’entrée
input_select.list_alarm
par son entité : alarm_control_panel.maison
et de remplacer l’appel au script.Nous allons maintenant très simplement ajouter le deuxième bouton (pour désactiver l’alarme) Pour ce faire, rien de plus simple, il suffit de copier-coller le code du custom_fields « zone_1 » et de le renommer en « zone_2 » puis gérer son positionnement puis modifier l’icône et le changement de couleur.
Pour illustrer l’exemple, j’ai créé deux scripts, un pour changer l’état de la liste déroulante sur « arming » puis « armed_away » après 3 secondes et un autre pour changer l’état de la liste déroulante sur « disarmed ».
Le premier script :
sequence:
- action: input_select.select_option
metadata: {}
data:
option: arming
target:
entity_id: input_select.list_alarm
- delay:
hours: 0
minutes: 0
seconds: 3
- action: input_select.select_option
metadata: {}
data:
option: armed_away
target:
entity_id: input_select.list_alarm
alias: list_alarm.arm
description: ""
et le deuxième :
sequence:
- action: input_select.select_option
metadata: {}
data:
option: disarmed
target:
entity_id: input_select.list_alarm
alias: list_alarm.disarm
description: ""
Le code actuel de la carte :
type: custom:button-card
aspect_ratio: 4/1
custom_fields:
zone_1:
card:
type: custom:button-card
icon: mdi:shield-lock
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: rgba(211,211,211,0.5)
- box-shadow: 2px 2px 4px 0px rgba(32,32,32,0.5)
- "--mdc-ripple-press-opacity": 0.12
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'red';
else if (states['input_select.list_alarm'].state == 'arming')
return 'orange';
else
return 'gray';
]]]
- animation: |
[[[
if (states['input_select.list_alarm'].state == 'arming')
return 'blink 2s ease infinite';
]]]
- width: 80%
tap_action:
action: call-service
service: script.list_alarm_arm
zone_2:
card:
type: custom:button-card
icon: mdi:shield-lock-open
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: rgba(211,211,211,0.5)
- box-shadow: 2px 2px 4px 0px rgba(32,32,32,0.5)
- "--mdc-ripple-press-opacity": 0.12
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'green';
else
return 'gray';
]]]
- width: 80%
tap_action:
action: call-service
service: script.list_alarm_disarm
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- border-width: 1px
- border-color: rgba(211,211,211,0.8)
- border-radius: 15px
- box-shadow: 5px 5px 10px 0px rgba(32,32,32,0.9)
- "--mdc-ripple-press-opacity": 0
custom_fields:
zone_1:
- position: absolute
- left: 8%
- top: 6%
zone_2:
- position: absolute
- left: 8%
- top: 52%
tap_action:
action: none
Nous allons maintenant parfaire un peu l’affichage visuel en modifiant l’aspect du bouton selon les états de l’alarme. La modification va consister à changer la transparence de la bordure du bouton et son ombrage en fonction de l’état : si l’alarme est dans l’état « arming » ou « armed_away », on va supprimer l’ombre du premier bouton et définir l’opacité de la couleur de bordure à 0.1 et inversement pour le deuxième bouton. Puis nous allons faire de même pour l’effet visuel lié au clic : quand l’état de l’alarme sera « arming » ou « armed_away », nous allons supprimer l’effet visuel lié au clic et nous le rétablirons dans l’état « disarmed » et inversement pour le deuxième bouton.
Le code :
type: custom:button-card
aspect_ratio: 4/1
custom_fields:
zone_1:
card:
type: custom:button-card
icon: mdi:shield-lock
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'rgba(211,211,211,0.1)';
else if (states['input_select.list_alarm'].state == 'arming')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'none';
else if (states['input_select.list_alarm'].state == 'arming')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return '0';
else if (states['input_select.list_alarm'].state == 'arming')
return '0';
else
return '0.12';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'red';
else if (states['input_select.list_alarm'].state == 'arming')
return 'orange';
else
return 'gray';
]]]
- animation: |
[[[
if (states['input_select.list_alarm'].state == 'arming')
return 'blink 2s ease infinite';
]]]
- width: 80%
tap_action:
action: call-service
service: script.list_alarm_arm
zone_2:
card:
type: custom:button-card
icon: mdi:shield-lock-open
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return '0';
else
return '0.12';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'green';
else
return 'gray';
]]]
- width: 80%
tap_action:
action: call-service
service: script.list_alarm_disarm
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- border-width: 1px
- border-color: rgba(211,211,211,0.8)
- border-radius: 15px
- box-shadow: 5px 5px 10px 0px rgba(32,32,32,0.9)
- "--mdc-ripple-press-opacity": 0
custom_fields:
zone_1:
- position: absolute
- left: 8%
- top: 6%
zone_2:
- position: absolute
- left: 8%
- top: 52%
tap_action:
action: none
Il reste cependant un détail à régler : l’appel au script… Il va falloir que le clic envoie un appel au script qu’en fonction de l’état de l’alarme : si l’alarme est armée ou en cours d’armement, il ne faut pas qu’un nouveau clic sur le premier bouton appelle à nouveau le script. Nous allons définir l’appel au script en fonction de l’état de l’alarme.
Le nouveau code :
type: custom:button-card
aspect_ratio: 4/1
custom_fields:
zone_1:
card:
type: custom:button-card
icon: mdi:shield-lock
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'rgba(211,211,211,0.1)';
else if (states['input_select.list_alarm'].state == 'arming')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'none';
else if (states['input_select.list_alarm'].state == 'arming')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return '0';
else if (states['input_select.list_alarm'].state == 'arming')
return '0';
else
return '0.12';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'red';
else if (states['input_select.list_alarm'].state == 'arming')
return 'orange';
else
return 'gray';
]]]
- animation: |
[[[
if (states['input_select.list_alarm'].state == 'arming')
return 'blink 2s ease infinite';
]]]
- width: 80%
tap_action:
action: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'none';
if (states['input_select.list_alarm'].state == 'arming')
return 'none';
else
return 'call-service';
]]]
service: script.list_alarm_arm
zone_2:
card:
type: custom:button-card
icon: mdi:shield-lock-open
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return '0';
else
return '0.12';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'green';
else
return 'gray';
]]]
- width: 80%
tap_action:
action: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'none';
else
return 'call-service';
]]]
service: script.list_alarm_disarm
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- border-width: 1px
- border-color: rgba(211,211,211,0.8)
- border-radius: 15px
- box-shadow: 5px 5px 10px 0px rgba(32,32,32,0.9)
- "--mdc-ripple-press-opacity": 0
custom_fields:
zone_1:
- position: absolute
- left: 8%
- top: 6%
zone_2:
- position: absolute
- left: 8%
- top: 52%
tap_action:
action: none
Pour finir, nous allons modifier un dernier détail : nous allons changer l’aspect du curseur en fonction de l’état de l’alarme et avoir la main quand le bouton sera cliquable et le curseur normal quand il ne le sera pas.
Pour ce faire nous allons ajouter la propriété « cursor » dans les différents éléments « card » de la carte « support » et des custom_fields et définir cette propriété sur « default » pour la carte « support » et soit sur « default » soit sur « hand » en fonction de l’état de l’alarme pour les deux custom_fields.
Pour ce faire nous allons ajouter la propriété « cursor » dans les différents éléments « card » de la carte « support » et des custom_fields et définir cette propriété sur « default » pour la carte « support » et soit sur « default » soit sur « hand » en fonction de l’état de l’alarme pour les deux custom_fields.
Le code modifié :
type: custom:button-card
aspect_ratio: 4/1
custom_fields:
zone_1:
card:
type: custom:button-card
icon: mdi:shield-lock
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'rgba(211,211,211,0.1)';
else if (states['input_select.list_alarm'].state == 'arming')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'none';
else if (states['input_select.list_alarm'].state == 'arming')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return '0';
else if (states['input_select.list_alarm'].state == 'arming')
return '0';
else
return '0.12';
]]]
- cursor: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'default';
else if (states['input_select.list_alarm'].state == 'arming')
return 'default';
else
return 'hand';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'red';
else if (states['input_select.list_alarm'].state == 'arming')
return 'orange';
else
return 'gray';
]]]
- animation: |
[[[
if (states['input_select.list_alarm'].state == 'arming')
return 'blink 2s ease infinite';
]]]
- width: 80%
tap_action:
action: |
[[[
if (states['input_select.list_alarm'].state == 'armed_away')
return 'none';
if (states['input_select.list_alarm'].state == 'arming')
return 'none';
else
return 'call-service';
]]]
service: script.list_alarm_arm
zone_2:
card:
type: custom:button-card
icon: mdi:shield-lock-open
show_icon: true
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- aspect-ratio: 1/1
- width: 50px
- border-radius: 50%
- border-width: 1px
- border-color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'rgba(211,211,211,0.1)';
else
return 'rgba(211,211,211,0.5)';
]]]
- box-shadow: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'none';
else
return '2px 2px 4px 0px rgba(32,32,32,0.5)';
]]]
- "--mdc-ripple-press-opacity": |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return '0';
else
return '0.12';
]]]
- cursor: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'default';
else
return 'hand';
]]]
icon:
- color: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'green';
else
return 'gray';
]]]
- width: 80%
tap_action:
action: |
[[[
if (states['input_select.list_alarm'].state == 'disarmed')
return 'none';
else
return 'call-service';
]]]
service: script.list_alarm_disarm
styles:
card:
- background-color: rgba(54, 54, 54, 1.0)
- border-width: 1px
- border-color: rgba(211,211,211,0.8)
- border-radius: 15px
- box-shadow: 5px 5px 10px 0px rgba(32,32,32,0.9)
- "--mdc-ripple-press-opacity": 0
- cursor: default
custom_fields:
zone_1:
- position: absolute
- left: 8%
- top: 6%
zone_2:
- position: absolute
- left: 8%
- top: 52%
tap_action:
action: none
Nous poursuivrons ce didacticiel en concevant un clavier numérique pour alarme sur le principe de la carte existante « Panneau d’alarme » **** A SUIVRE ****
En attendant cette suite, nous allons voir comment télécharger et utiliser une police de caractère non standard. Nous utiliserons cette police pour reproduire un compteur Linky afin de lire les informations de la TIC retournées (pour ma part) par un module zLinky de Lixee.
Le but sera d’arriver à ce visuel :

Je poste dès à présent le code complet de la custom:button-card ainsi que les ressources utilisées pour obtenir ce visuel. Nous détaillerons le code plus loin.
Le code utilisé :
type: custom:button-card
custom_fields:
linky:
card:
type: custom:button-card
styles:
card:
- width: 560px
- height: 840px
- background-color: rgba(168,190,45,1.0)
- border-radius: 40px
led_box:
card:
type: custom:button-card
styles:
card:
- width: 46px
- height: 34px
- border-radius: 4px
- background: >-
linear-gradient(225deg, rgba(168, 190, 45,1.0), rgba(192, 192,
192,0.2))
- border: 1px rgba(255,255,255,0.2) outset
- box-shadow: inset -2px 2px 2px rgba(28,28,28,0.2)
led_background:
card:
type: custom:button-card
styles:
card:
- width: 23px
- height: 17px
- border-radius: 4px
- background-color: rgba(28,28,28,1.0)
led:
card:
type: custom:button-card
styles:
card:
- width: 17px
- height: 17px
- border-radius: 0px
- background: |
[[[
return `radial-gradient(ellipse at center,
rgba(255, 165, 0, 1) 20%,
rgba(255, 165, 0, 0.2) 80%,
rgba(28, 28, 28, 1) 100%)`;
]]]
- animation: |
[[[
const value = states['sensor.entree_zlinky_lixee_sinsts']?.state || 0;
if (value <= 1000) {
return 'blink 1.8s infinite';
} else if (value <= 2000) {
return 'blink 1.6s infinite';
} else if (value <= 3000) {
return 'blink 1.4s infinite';
} else if (value <= 4000) {
return 'blink 1.2s infinite';
} else if (value <= 5000) {
return 'blink 1.0s infinite';
} else if (value <= 6000) {
return 'blink 0.8s infinite';
} else if (value <= 7000) {
return 'blink 0.6s infinite';
} else if (value <= 8000) {
return 'blink 0.4s infinite';
} else {
return 'blink 0.2s infinite';
}
]]]
extra_styles: |
@keyframes blink {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
logo:
card:
type: custom:button-card
styles:
card:
- background-image: url(/local/images/linkylogo.png)
- width: 192px
- height: 54px
- background-size: cover
- background-position: center
- border-radius: 0px
- border: none
- background-color: rgba(168,190,45,1.0)
box:
card:
type: custom:button-card
name: Mon compteur Linky par @Cleya
styles:
card:
- width: 342px
- height: 404px
- border-radius: 40px
- border-size: 3px
- border-color: rgba(28,28,28,0.5)
- background: >-
radial-gradient(circle, rgba(234, 234, 234,1.0), rgba(160, 160,
160,1.0))
- box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1)
name:
- font-size: 18px
- font-style: italic
- color: rgba(28,28,28,0.1)
- position: absolute
- top: 30px
- left: 0
- width: 100%
- text-align: center
- text-shadow: 0px 2px 4px rgba(28, 28, 28, 0.2)
back_screen:
card:
type: custom:button-card
styles:
card:
- width: 235px
- height: 264px
- background-color: rgba(179,178,173,1.0)
- border-radius: 10px
- border-width: 1px
- border-color: rgba(28,28,28,0.1)
- box-shadow: inset -1px 1px 6px rgba(28, 28, 28, 0.1)
screen:
card:
type: custom:button-card
name: |
[[[
const affichage = states['input_number.affichage_linky']?.state || '0';
const sensors = states;
if (affichage === '1.0') {
return (sensors['sensor.entree_zlinky_lixee_current_price']?.state || '-') + '<br>NOM DU CONTRAT';
} else if (affichage === '2.0') {
return (sensors['sensor.entree_zlinky_lixee_east']?.state || '-') + ' kWh<br>' +
(sensors['sensor.entree_zlinky_lixee_current_price']?.state || '-');
} else if (affichage === '3.0') {
return (sensors['sensor.entree_zlinky_lixee_sinsts']?.state || '-') + ' VA<br>PUIS APP SOUTIR';
} else if (affichage === '4.0') {
return (sensors['sensor.entree_zlinky_lixee_smaxn']?.state || '-') + ' VA<br>PUIS MAX SOUTIR';
} else if (affichage === '5.0') {
return (sensors['sensor.entree_zlinky_lixee_pref']?.state || '-') + ' kVA<br>P SOUSCRITE';
} else if (affichage === '6.0') {
return (sensors['sensor.entree_zlinky_lixee_pcoup']?.state || '-') + '000 VA<br>PUISSANCE COUP';
} else if (affichage === '7.0') {
return (sensors['sensor.entree_zlinky_lixee_site_id']?.state || '-') + '<br>NUMERO DE PRM';
} else if (affichage === '8.0') {
const value = sensors['sensor.entree_zlinky_lixee_current_date']?.state || '';
if (value.length >= 6) {
const lastSix = value.slice(-6);
const formattedTime = lastSix.slice(0, 2) + ':' + lastSix.slice(2, 4) + ':' + lastSix.slice(4, 6);
return formattedTime + '<br>HEURE COURANTE';
}
return '-<br>HEURE COURANTE';
} else if (affichage === '9.0') {
const value = sensors['sensor.entree_zlinky_lixee_current_date']?.state || '';
if (value.length >= 12) {
const lastTwelve = value.slice(-12);
const formattedDate = lastTwelve.slice(0, 2) + '/' + lastTwelve.slice(2, 4) + '/' + lastTwelve.slice(4, 6);
return formattedDate + '<br>DATE COURANTE';
}
return '-<br>DATE COURANTE';
} else if (affichage === '10.0') {
const vtic = sensors['sensor.entree_zlinky_lixee_vtic']?.state || '0';
return vtic === '1' ? 'HISTORIQUE<br>MODE TIC' : 'STANDARD<br>MODE TIC';
} else if (affichage === '11.0') {
return (sensors['sensor.entree_zlinky_lixee_meter_serial_number']?.state || '-') + '<br>NUMERO SERIE';
} else if (affichage === '12.0') {
return (sensors['sensor.entree_zlinky_lixee_eait']?.state || '-') + ' kWh<br>INDEX INJECTION';
} else if (affichage === '13.0') {
return (sensors['sensor.entree_zlinky_lixee_message1']?.state || '-');
} else {
return '-';
}
]]]
styles:
card:
- width: 235px
- height: 92px
- background-color: rgba(163,230,223,1.0)
- border: 2px rgba(163,230,223,0.4) inset
- border-radius: 0
name:
- font-family: Subway Ticker
- font-size: 22px
- color: rgba(28,28,28,0.8)
- position: absolute
- top: 6px
- left: 0
- width: 100%
- text-align: center
- line-height: 1.5
less_button:
card:
type: custom:button-card
icon: mdi:minus
styles:
card:
- width: 97px
- height: 46px
- background-color: rgba(179,178,173,1.0)
- border-radius: 0
- border: 2px rgba(211,211,211,0.8) outset
icon:
- height: 80%
tap_action:
action: call-service
service: script.decrement_affichage_linky
more_button:
card:
type: custom:button-card
icon: mdi:plus
styles:
card:
- width: 97px
- height: 46px
- background-color: rgba(179,178,173,1.0)
- border-radius: 0
- border: 2px rgba(211,211,211,0.8) outset
icon:
- height: 80%
tap_action:
action: call-service
service: script.increment_affichage_linky
rearm_led:
card:
type: custom:button-card
styles:
card:
- width: 97px
- height: 10px
- background-color: rgba(28,64,28,0.9)
- border-radius: 0
- border: 2px rgba(28,28,28,0.2) inset
depressed_area:
card:
type: custom:button-card
styles:
card:
- width: 296px
- height: 112px
- border-radius: 4px
- background: >-
radial-gradient(circle, rgba(168,190,45,1.0) 10%,
rgba(161,183,43,1.0) 100%)
- border: 1px rgba(255,255,255,0.2) outset
- box-shadow: inset -2px 2px 2px rgba(28,28,28,0.2)
decor:
card:
type: custom:button-card
custom_fields:
breach:
card:
type: custom:button-card
styles:
card:
- width: 68px;
- height: 14px;
- background: conic-gradient(rgb(112,136,21) 0%, rgb(161,183,43) 100%)
- border: none
- border-radius: 0
- box-shadow: inset -2px 2px 2px rgba(28,28,28,0.2)
ring_background:
card:
type: custom:button-card
styles:
card:
- width: 14px
- height: 40px
- border-radius: 0px
- background: rgba(28,28,28,0.5)
ring:
card:
type: custom:button-card
styles:
card:
- width: 12px
- height: 40px
- border-radius: 7px
- background: |
[[[
return `linear-gradient(to bottom,
rgba(200, 200, 200, 1) 0%,
rgba(255, 255, 255, 0.8) 30%,
rgba(200, 200, 200, 0.8) 70%,
rgba(150, 150, 150, 1) 100%)`;
]]]
- box-shadow: >-
0px 0px 6px rgba(0, 0, 0, 0.6), inset 0px 2px 4px rgba(255,
255, 255, 0.4)
- border: 1px solid rgba(0, 0, 0, 0.4)
- margin: auto
styles:
card:
- width: 82px
- height: 48px
- background-color: rgba(168,190,45,1.0)
- border-radius: 0
- border: none
custom_fields:
breach:
- position: absolute
- top: 37%
- left: 8%
ring_background:
- position: absolute
- top: 8.2%
- left: 40.5%
ring:
- position: absolute
- top: 8.2%
- left: 41.9%
styles:
card:
- background-color: rgba(28,28,28,1.0)
- width: 600px
- height: 885px
- opacity: 1
- cursor: default
custom_fields:
linky:
- position: absolute
- top: 2.5%
- left: 3.5%
led_box:
- position: absolute
- top: 10.5%
- left: 46.5%
led_background:
- position: absolute
- top: 11.6%
- left: 48.4%
led:
- position: absolute
- top: 11.6%
- left: 48.9%
logo:
- position: absolute
- top: 15%
- left: 34%
box:
- position: absolute
- top: 22.9%
- left: 22%
back_screen:
- position: absolute
- top: 32%
- left: 30.7%
screen:
- position: absolute
- top: 41.7%
- left: 30.7%
less_button:
- position: absolute
- top: 62.1%
- left: 33.65%
more_button:
- position: absolute
- top: 62.1%
- left: 51.1%
rearm_led:
- position: absolute
- top: 67.3%
- left: 51.1%
depressed_area:
- position: absolute
- top: 72%
- left: 26%
decor:
- position: absolute
- top: 88.5%
- left: 43.8%
tap_action:
action: none
L’image du logo « Linky » (ça sera la seule image utilisée, les autres éléments graphiques ot été fait à partir de custom_fields) :
Le script utilisé pour le bouton « + » :
sequence:
- alias: Incrémenter affichage Linky
sequence:
- data:
entity_id: input_number.affichage_linky
value: >
{% set current = states('input_number.affichage_linky') | int(0) %}
{% if current < 13 %}
{{ current + 1 }}
{% else %}
1
{% endif %}
action: input_number.set_value
alias: increment_affichage_linky
description: ""
Le script pour le bouton « - » :
sequence:
- alias: Décrémenter affichage Linky
sequence:
- data:
entity_id: input_number.affichage_linky
value: >
{% set current = states('input_number.affichage_linky') | int(0) %}
{% if current > 1 %}
{{ current - 1 }}
{% else %}
13
{% endif %}
action: input_number.set_value
alias: decrement_affichage_linky
description: ""
Nous avons créé une entrée numérique (« input_number ») nommée «
affichage_linky
» pour enregistrer l’élément de l’affichage en cours (l’input_number a été défini avec une valeur minimale de 1, une valeur maximale de 13 et un pas de 1).Nous avons téléchargé la police « Subway Ticker Font
» ici :
Une fois la police téléchargée, il va falloir extraire le fichier
.ttf
du dossier compressé (.zip
) et le mettre dans un répertoire « fonts » placé dans le répertoire « www » :On renommera ensuite le fichier
.tff
en SubwayTicker.ttf
. Une fois cela fait, on va créer un nouveau fichier à la racine du répertoire « www » qu’on appelera custom-styles.css
et on éditera ce fichier afin de coller le texte suivant :@font-face {
font-family: 'Subway Ticker';
src: url('/local/fonts/SubwayTicker.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
Cela fait, nous allons dire à Home Assistant de charger cette ressource en l’ajoutant aux ressources Lovelace :
Pour l’ajouter, nous allons cliquer sur les trois points en haut à droite de l’onglet « Tableaux de bord » :
Puis sur « Ressources » :
Et enfin sur le bouton « + AJOUTER UNE RESSOURCE » :

Nous allons ajouter ensuite le fichier
.css
en inscrivant son URL et en cochant « Feuille de style » puis en cliquant sur « CREER » :Une fois ces opérations réalisées, il faudra recharger Home Assistant et vider le cache du navigateur.