Bouton alarme Jablotron

Bonjour à tous,

@anon51798830 Il y a quelques mois, tu m’avais aidé à créer des boutons pour le portail et pour le garage dans un contexte qui n’était pas facile car le retour d’état du portail passait par la connexion normalement dédiée à la lampe portail, lampe que je n’avais pas. ça nous avait pris 1 jour avec @WarC0zes qui nous aidait aussi.

Aujourd’hui, je viens de faire mettre à jour les éléments de mon alarme Jablotron vers une alarme Jablotron JA103KRY avec module LAN et module GSM (si INternet ne fonctionne pas).
J’ai répondu avec quelques photos ici: Intégration jablotron - #2 par Matt1

Question: serait-il possible d’ajouter 2 boutons (Armer/Désarmer) en tant que premiers boutons de l’horizontal stack des 3 boutons que tu m’avais réalisé ?

Je n’arrive pas bien avec la carte bouton…
Je te mets en dessous le code actuel de l’horizontal stack des 3 boutons (dernière version que je l’ai légèrement adapté depuis la dernière fois).

J’ai conscience que ma demande est peut-être un peu complexe et que je suis en demande sans proposition avec une carte bouton, ce n’est pas grave si ce n’est pas possible, je comprends :slightly_smiling_face:

Bonne journée et bon week-end,

Ce que j’ai fait pour l’alarme:

type: custom:vertical-stack-in-card
cards:
  - type: horizontal-stack
    cards:
      - show_name: false
        show_icon: true
        type: button
        tap_action:
          action: toggle
        entity: script.armer_alarme
        show_state: false
        icon_height: 50px
        hold_action:
          action: none
        card_mod:
          style: |
            ha-card {
              border: 0px;
            }
            ha-state-icon {
              {% if states('alarm_control_panel.maison') == 'armed_away' %}
                --card-mod-icon-color: red
              {% elif states('alarm_control_panel.maison') == 'arming' %}
                animation: pulse 2s linear infinite;
                --card-mod-icon-color: orange
              {% elif states('alarm_control_panel.maison') == 'disarmed' %}
                --card-mod-icon-color: grey
              {% else %}
                animation: pulse 2s linear infinite;
                --card-mod-icon-color: red
              {% endif %}            
            }
      - show_name: false
        show_icon: true
        type: button
        tap_action:
          action: toggle
        entity: script.desarmer_alarme
        show_state: false
        icon_height: 50px
        hold_action:
          action: none
        card_mod:
          style: |
            ha-card {
              border: 0px;
            }
            ha-state-icon {
              {% if states('alarm_control_panel.maison') == 'disarmed' %}
                --card-mod-icon-color: green
              {% elif states('alarm_control_panel.maison') == 'armed_away' %}
                --card-mod-icon-color: grey
              {% elif states('alarm_control_panel.maison') == 'arming' %}
                --card-mod-icon-color: grey
              {% else %}
                animation: pulse 2s linear infinite;
                --card-mod-icon-color: red
              {% endif %}            
            }

Le code des 3 boutons « Cleya »:

type: custom:button-card
aspect_ratio: 14/3
custom_fields:
  cardGaragePortail:
    card:
      type: custom:button-card
      name: Portail &<br/>Garage
      icon: mdi:gate-open
      aspect_ratio: 1.6/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
               ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)'; 
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
              ]]]          
      tap_action:
        action: call-service
        service: script.portail_et_garage
      hold_action:
        action: none
  cardGarage:
    card:
      type: custom:button-card
      entity: cover.porte_de_garage
      name: Garage
      icon: mdi:garage
      show_label: true
      label: |
        [[[
          if (states['cover.porte_de_garage'].state == 'closed')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['cover.porte_de_garage'].state == 'open')
            return '<font color= "green"><b>Ouvert</font>';
          else if (states['cover.porte_de_garage'].state == 'closing')
            return '<font color= "orange"><b>Fermeture</font>';
          else if (states['cover.porte_de_garage'].state == 'opening')
            return '<font color= "orange"><b>Ouverture</font>';
        ]]]
      aspect_ratio: 1.6/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,1.05)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]          
        label:
          - animation: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closing')
                  return 'blink 2s ease infinite';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'blink 2s ease infinite';
              ]]]
      tap_action:
        action: toggle
      hold_action:
        action: none
  cardportail:
    card:
      type: custom:button-card
      entity: switch.portail
      name: Portail
      icon: mdi:gate
      show_label: true
      label: |
        [[[
          if (states['binary_sensor.portail_mouvement'].state == 'off')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['binary_sensor.portail_mouvement'].state == 'on')
            return '<font color= "green"><b>Ouvert</font>';
        ]]]
      aspect_ratio: 1.6/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
              ]]]          
      tap_action:
        action: toggle
      hold_action:
        action: none
styles:
  card:
    - background-color: rgba(32, 32, 32, 0.9)
  custom_fields:
    cardGaragePortail:
      - width: 32%
      - position: absolute
      - left: 1%
      - top: 4%
    cardportail:
      - width: 32%
      - position: absolute
      - left: 34%
      - top: 4%
    cardGarage:
      - width: 32%
      - position: absolute
      - left: 67%
      - top: 4%

Ma configuration


[center]## System Information

version core-2025.1.2
installation_type Home Assistant OS
dev false
hassio true
docker true
user root
virtualenv false
python_version 3.13.1
os_name Linux
os_version 6.6.66-haos
arch x86_64
timezone Europe/Brussels
config_dir /config
Home Assistant Community Store
GitHub API ok
GitHub Content ok
GitHub Web ok
HACS Data ok
GitHub API Calls Remaining 5000
Installed Version 2.0.3
Stage running
Available Repositories 1503
Downloaded Repositories 46
Home Assistant Cloud
logged_in true
subscription_expiration 28 avril 2025 à 02:00
relayer_connected true
relayer_region eu-central-1
remote_enabled true
remote_connected true
alexa_enabled false
google_enabled true
cloud_ice_servers_enabled true
remote_server eu-central-1-19.ui.nabu.casa
certificate_status ready
instance_id f0fd017040d14711b17f54352dde68e6
can_reach_cert_server ok
can_reach_cloud_auth ok
can_reach_cloud ok
Home Assistant Supervisor
host_os Home Assistant OS 14.1
update_channel stable
supervisor_version supervisor-2024.12.3
agent_version 1.6.0
docker_version 27.2.0
disk_total 938.2 GB
disk_used 18.3 GB
healthy true
supported true
host_connectivity true
supervisor_connectivity true
ntp_synchronized true
virtualization
board generic-x86-64
supervisor_api ok
version_api ok
installed_addons Matter Server (7.0.0), Terminal & SSH (9.16.0), File editor (5.8.0), Samba share (12.4.0), Home Assistant Google Drive Backup (0.112.1), Studio Code Server (5.18.0), Spotify Connect (0.13.0), OpenThread Border Router (2.13.0), Mosquitto broker (6.5.0), Frigate (0.14.1)
Dashboards
dashboards 2
resources 39
views 9
mode storage
Recorder
oldest_recorder_run 8 janvier 2025 à 02:43
current_recorder_run 18 janvier 2025 à 07:41
estimated_db_size 300.85 MiB
database_engine sqlite
database_version 3.47.1
Spotify
api_endpoint_reachable ok
[/center] Comment récupérer ma configuration : Dans votre HA, Menu latéral `Paramètres` > `Système` > `Corrections` puis les trois petits points en haut a droite > `Informations Système` puis une fois en bas `Copier` ___

Salut, je te fais ça demain. Bonne soirée

Ah bien déjà merci beaucoup @anon51798830 pour ta réponse positive :pray:
En fonction de comment c’est le plus simple, cela peut aussi être un seul bouton qui est rouge quand c’est armé et vert quand c’est désarmé.

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.

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 :

essai

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 » :
image
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.

2 « J'aime »

Bonjour @anon51798830
Merci beaucoup pour ces superbes explications !!
Grâce à toi, je suis « rentré » dans le code, j’ai lu et essayé de comprendre point par point.
Alors, je ne suis pas certain d’avoir tout compris, en particulier avec les ratios pour déterminer la taille des cartes et des icônes… Mais j’arrive à l’image que tu vois ci-dessous en chipotant (je te mets la copie complète de ma page d’accueil car comme cela, tu vois aussi que je travaille en 2 colonnes, ce qui m’a semblé le plus efficace pour passer du PC au kiosque tablette en mode paysage sur le mur du
salon).

Ce que j’aimerais encore faire, c’est mettre :

  1. l’icône de la carte "Armer " en rouge quand son état est « armed_away », en orange clignotant quand l’état est « arming », autrement en gris. pendant l’armement (comme dans mon code initial).
  2. l’îcone de la carte « Désarmer » en vert quand son état est « disarmed », autrement en gris (pas besoin d’orange clignotant car le désarmement est instantané).

Et voici mon code modifié en l’état actuel des choses:

type: custom:button-card
aspect_ratio: 4.4/1
custom_fields:
  cardArmer:
    card:
      type: custom:button-card
      icon: mdi:shield-lock
      styles:
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - aspect-ratio: 1.1/1
          - width: 45%
          - border-radius: 50%
          - border: 2px rgba (211,211,211,1.0)
          - left: 27.5%
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - color: grey
          - width: 100%
      tap_action:
        action: call-service
        service: script.armer_alarme
  cardDésarmer:
    card:
      type: custom:button-card
      icon: mdi:shield-lock-open
      styles:
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - aspect-ratio: 1.1/1
          - width: 45%
          - border-radius: 50%
          - border: 2px rgba (211,211,211,1.0)
          - left: 27.5%
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - color: grey
          - width: 100%
      tap_action:
        action: call-service
        service: script.desarmer_alarme
  cardGaragePortail:
    card:
      type: custom:button-card
      name: Portail &<br/>Garage
      icon: mdi:gate-open
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
               ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)'; 
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
              ]]]          
      tap_action:
        action: call-service
        service: script.portail_et_garage
      hold_action:
        action: none
  cardGarage:
    card:
      type: custom:button-card
      entity: cover.porte_de_garage
      name: Garage
      icon: mdi:garage
      show_label: true
      label: |
        [[[
          if (states['cover.porte_de_garage'].state == 'closed')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['cover.porte_de_garage'].state == 'open')
            return '<font color= "green"><b>Ouvert</font>';
          else if (states['cover.porte_de_garage'].state == 'closing')
            return '<font color= "orange"><b>Fermeture</font>';
          else if (states['cover.porte_de_garage'].state == 'opening')
            return '<font color= "orange"><b>Ouverture</font>';
        ]]]
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,1.05)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]          
        label:
          - animation: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closing')
                  return 'blink 2s ease infinite';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'blink 2s ease infinite';
              ]]]
      tap_action:
        action: toggle
      hold_action:
        action: none
  cardPortail:
    card:
      type: custom:button-card
      entity: switch.portail
      name: Portail
      icon: mdi:gate
      show_label: true
      label: |
        [[[
          if (states['binary_sensor.portail_mouvement'].state == 'off')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['binary_sensor.portail_mouvement'].state == 'on')
            return '<font color= "green"><b>Ouvert</font>';
        ]]]
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(32, 32, 32, 0.9)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
              ]]]
          - width: 42px
          - height: 40px
          - color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
              ]]]          
      tap_action:
        action: toggle
      hold_action:
        action: none
styles:
  card:
    - background-color: rgba(32, 32, 32, 0.9)
    - "--mdc-ripple-press-opacity\"": 0
  custom_fields:
    cardArmer:
      - width: 24%
      - position: absolute
      - left: 1%
      - top: 4%
    cardDésarmer:
      - width: 24%
      - position: absolute
      - left: 1%
      - top: 52%
    cardGaragePortail:
      - width: 24%
      - position: absolute
      - left: 26%
      - top: 4%
    cardPortail:
      - width: 24%
      - position: absolute
      - left: 51%
      - top: 4%
    cardGarage:
      - width: 24%
      - position: absolute
      - left: 76%
      - top: 4%

Bonjour @Matt1,

Petite question, pourquoi ne pas utiliser qu’un seul et même bouton qui indiquerait toutes les infos que tu souhaites :

  • Icône cadena ouvert en vert lorsque l’alarme est désactivée
  • Icône cadena fermé orange lorsqu’elle s’arme
  • Icône cadena fermé rouge lorsqu’elle est armée

Le tout avec l’état de l’alarme indiqué en texte sous l’icône, donc la même logique que pour tes autres boutons à droite.

Tu gagnerais en place et tu garderais le même niveau d’informations.

Bonjour @Integra
Ah mais moi je veux bien, c’est simplement que je ne sais pas comment il faut faire et que je pensais que ce n’était pas possible, d’où ma demande de 2 boutons à @anon51798830 :sweat_smile:
Car j’ai constaté l’entité de mon alarme ne fonctionne pas comme un simple bouton. D’ailleurs si je prends la carte bouton, cela ne fonctionne pas comme avec un service toggle simple.
C’est pour cette raison que j’ai créé 2 scripts: 1 script pour activer l’alarme qui appelle le service « Armer alarme » et qui pointe vers l’entité de mon alarme. Et un autre script qui appelle le service « Désarmer alarme » et qui pointe vers la même et unique entité de mon alarme avec application d’un code de désarmement que je peux encoder dans le service de désarmement de l’alarme.
Tu as une alarme et tu as réussi à ne mettre qu’un seul bouton ? :thinking:

Bonjour @Matt1

Oui c’est possible, je te dirai comment faire un peu plus tard. Je continue le didacticiel pour l’instant :grin:. Il suffit de mettre des conditions sur l’action, de la même manière que tu utilises des conditions pour changer la couleur de l’icône.

Sinon, il est aussi possible d’avoir deux boutons (custom_fields) superposés et d’afficher uniquement celuis qui correspond à l’état de l’alarme (le bouton pour la désactiver si elle est en armed_away ou le bouton pour l’activer si elle est en disarmed).

Bonjour @anon51798830
Ok, merci ! C’est une super nouvelle ça !
On fait comme ça, oui. Je vais toujours continuer ton didacticiel, puis j’essayerai avec un bouton par la suite.
Merci beaucoup en tout cas :pray:

Oui je te confirme, c’est tout à fait possible de tout regrouper dans une seule et même carte de type Button card.

Je ne veux pas parasiter le didacticiel de @anon51798830 donc je le laisse t’apporter la solution pour ça :wink:.

Et concernant ton script, tu peux logiquement tout regrouper dans un seul et même script avec un bloc de construction type « Si > alors > sinon ». À savoir : si alarme désactivée > alors l’activer > sinon la désactiver.

Pour resumer, une seule Button card assez basique qui renvoie l’état de ton alarme avec declenchement de ton script lors d’un appui.

Pour mon alarme, je n’utilise pas de bouton je passe par la carte Alarmo card, qui m’affiche le clavier a code pour la désactivation etc. Mais en soit je pourrai passer par une Button card qui m’affiche ledit clavier dans une popup lors d’un appui… . Juste une histoire de goût.

Merci pour ce complément d’infos @Integra
Cleya vient de compléter fameusement son didacticiel. Je vais essayer tout cela :slightly_smiling_face:
J’avais aussi téléchargé Alarmo mais j’ai finalement préféré passer par un simple bouton. En plus, c’est uniquement sur des appareils personnels et sécurisés qu’on pourrait désactiver l’alarme sans taper physiquement un mot de passe puisque cela sera automatisé, donc ça me dérange pas trop.
Mais comme tu dis, c’est une question de goût, et après il faut par contre être capable de réaliser selon ses envies

Oui dans ton cas l’utilisation d’Alarmo n’est pas nécessaire car tu as un vrai système d’alarme externalisé. Donc un simple bouton + script suffit sur des appareils dont l’accès est déjà sécurisé.

Dans mon cas, les seuls appareils sur lesquels j’applique ce principe sont les smartphones avec un bouton dans la barre des raccourcis/notification pour activer/desactiver l’alarme sans passer par l’app et sans avoir à taper de code.

En effet et le forum est bien pratique pour trouver toutes les infos dont on a besoin pour les réaliser.

pareil, je crée des boutons raccourcis sur les smartphones de mon fils et le mien :slight_smile:

1 « J'aime »

Bonjour @anon51798830
Voilà ci-dessous ce à quoi je suis arrivé ! Je suis très content :smiley: Encore merci pour ton temps :pray:
J’ai tout lu et j’ai opté pour une solution hybride en tenant compte du fait que je pouvais créer un seul script pour armer et désarmer mon alarme (merci aussi @Integra )

J’ai utilisé ce script unique dans le code de la carte de Cleya.
Vu le script, lorsque je rappuie sur le bouton et que l’alarme est en cours d’armement, elle se désarme instantanément.
Je n’ai pas pu utiliser la fonction « si non » du « Si alors » car j’avais des bugs. Du coup, j’ai utilisé le bloc de construction « Choisir » et cela semble bien fonctionner.

Dans le code de la carte, j’ai essayé de me rapprocher le plus possible de la couleur de fond des supports lorsqu’on travaille en mode sombre. D’après mes tests, je pense que c’est le rgba(28, 28, 28, 1.0). Merci @anon51798830 pour tes explications à ce sujet, je comprends mieux les codes rgba à présent !

Je me suis basé sur les codes des autres boutons, également créés par Cleya, pour réaliser les changements de couleurs des icônes et des « labels » en fonction du retour d’état de mon entité alarme (pas l’entité du script donc mais bien de l’alarme). Ainsi, je n’ai pas eu besoin de créer de liste dans les entrées pour réaliser des tests, bien que j’ai déjà créé pas mal d’entrées entre autres pour la gestion de mon chauffage (pour lequel Versatile Thermostat gère une bonne partie mais pas tout).

Danq mon cas, l’état (label) clignote en orange quand l’alarme est en cours d’armement, comme l’état du garage clignote en orange quand il est en cours ouverture ou fermeture.

J’ai aussi appliqué l’ombrage autour de l’îcone de la même manière que pour le portail et le garage.

Et grâce à Cleya, je suis aujourd’hui en mesure de changer les couleurs d’ombrage, d’arrière plan de l’îcone ou de l’icône. Il suffit simplement que je cherche le bon code rgba via Google.

J’ai eu un peu plus de mal avec la taille de l’icône. Si j’ai bien compris, le fait de travailler en % (et pas en px) permet d’obtenir quelque chose de plus « responsive » lorsqu’on passe du PC à une tablette ou à un smartphone. Mais quand je travaille en pourcent avec width et height, j’ai du mal à gérer la taille souhaitée de l’icône car c’est par rapport au support: elle se met par exemple dans le coin supérieur gauche du support en devenant plus petite mais ne reste pas au centre de son support comme avec les px…

Autre point: je sais qu’il y a des lignes de code que je pourrais enlever, par exemple des box-shadow avec 0px partout. Mais je les garde afin de ne pas oublier que je peux aussi rajouter cela :sweat_smile:

Encore un grand bravo pour la vulgarisation de ces explications complexes pour un amateur, @anon51798830 !

Le code de la carte complète avec les 4 icônes pour l’alarme, le portail et le garage:

type: custom:button-card
aspect_ratio: 4.5/1
custom_fields:
  cardAlarme:
    card:
      type: custom:button-card
      icon: mdi:shield-home
      name: Alarme
      aspect_ratio: 1.2/1
      show_label: true
      label: |
        [[[
          if (states['alarm_control_panel.alarme_maison'].state == 'armed_away')
            return '<font color= "red"><b>Armé</font>';
          else if (states['alarm_control_panel.alarme_maison'].state == 'disarmed')
            return '<font color= "green"><b>Désarmé</font>';
          else if (states['alarm_control_panel.alarme_maison'].state == 'arming')
            return '<font color= "orange"><b>Armement</font>';
        ]]]
      styles:
        card:
          - background-color: rgba(28, 28, 28, 1.0)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        icon:
          - border-radius: 50%
          - border: none
          - width: 42px
          - height: 42px
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['alarm_control_panel.alarme_maison'].state == 'armed_away')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'disarmed')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'arming')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['alarm_control_panel.alarme_maison'].state == 'armed_away')
                  return 'rgba(255,0,0,0.5)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'disarmed')
                  return 'rgba(0,128,0,0.5)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'arming')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - color: |
              [[[
                if (states['alarm_control_panel.alarme_maison'].state == 'armed_away')
                  return 'rgba(255,0,0,1.05)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'disarmed')
                  return 'rgba(0,255,0,1.0)';
                else if (states['alarm_control_panel.alarme_maison'].state == 'arming')
                  return 'rgba(255,140,0,0.5)';
              ]]]
        label:
          - animation: |
              [[[
                if (states['alarm_control_panel.alarme_maison'].state == 'arming')
                  return 'blink 2s ease infinite';
              ]]]
      tap_action:
        action: call-service
        service: script.alarme_maison
  cardGaragePortail:
    card:
      type: custom:button-card
      name: Portail &<br/>Garage
      icon: mdi:gate-open
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(28, 28, 28, 1.0)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
               ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 42px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)'; 
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closed' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'open' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'opening' && states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,140,0,1.0)';
              ]]]          
      tap_action:
        action: call-service
        service: script.portail_et_garage
      hold_action:
        action: none
  cardGarage:
    card:
      type: custom:button-card
      entity: cover.porte_de_garage
      name: Garage
      icon: mdi:garage
      show_label: true
      label: |
        [[[
          if (states['cover.porte_de_garage'].state == 'closed')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['cover.porte_de_garage'].state == 'open')
            return '<font color= "green"><b>Ouvert</font>';
          else if (states['cover.porte_de_garage'].state == 'closing')
            return '<font color= "orange"><b>Fermeture</font>';
          else if (states['cover.porte_de_garage'].state == 'opening')
            return '<font color= "orange"><b>Ouverture</font>';
        ]]]
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(28, 28, 28, 1.0)
          - box-shadow: 0px 0px 0px 0px rgba(32, 32, 32, 0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return '0px 0px 5px 5px rgba(255,140,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,128,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]
          - width: 42px
          - height: 42px
          - color: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closed')
                  return 'rgba(255,0,0,1.05)';
                else if (states['cover.porte_de_garage'].state == 'open')
                  return 'rgba(0,255,0,1.0)';
                else if (states['cover.porte_de_garage'].state == 'closing')
                  return 'rgba(255,140,0,0.5)';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'rgba(255,140,0,0.5)';
              ]]]          
        label:
          - animation: |
              [[[
                if (states['cover.porte_de_garage'].state == 'closing')
                  return 'blink 2s ease infinite';
                else if (states['cover.porte_de_garage'].state == 'opening')
                  return 'blink 2s ease infinite';
              ]]]
      tap_action:
        action: toggle
      hold_action:
        action: none
  cardPortail:
    card:
      type: custom:button-card
      entity: switch.portail
      name: Portail
      icon: mdi:gate
      show_label: true
      label: |
        [[[
          if (states['binary_sensor.portail_mouvement'].state == 'off')
            return '<font color= "red"><b>Fermé</font>';
          else if (states['binary_sensor.portail_mouvement'].state == 'on')
            return '<font color= "green"><b>Ouvert</font>';
        ]]]
      aspect_ratio: 1.2/1
      styles:
        name:
          - font-size: 0.8em
          - justify-self: middle
          - align-self: end
          - color: rgba(255,255,255,0.6)
        card:
          - background-color: rgba(28, 28, 28, 1.0)
          - box-shadow: 0px 0px 0px 0px rgba(32,32,32,0.9)
          - border: none
          - "--mdc-ripple-press-opacity": 0.12
        icon:
          - border-radius: 50%
          - border: none
          - box-shadow: 0px 0px 5px 5px rgba(0,128,0,0.5)
          - box-shadow: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return '0px 0px 5px 5px rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return '0px 0px 5px 5px rgba(0,128,0,0.5)';
              ]]]
          - background-color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,0.5)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,128,0,0.5)';
              ]]]
          - width: 42px
          - height: 42px
          - color: |
              [[[
                if (states['binary_sensor.portail_mouvement'].state == 'off')
                  return 'rgba(255,0,0,1.05)';
                else if (states['binary_sensor.portail_mouvement'].state == 'on')
                  return 'rgba(0,255,0,1.0)';
              ]]]          
      tap_action:
        action: toggle
      hold_action:
        action: none
styles:
  card:
    - background-color: rgba(28, 28, 28, 1.0)
    - "--mdc-ripple-press-opacity\"": 0
  custom_fields:
    cardAlarme:
      - width: 24%
      - position: absolute
      - left: 0.8%
      - top: 4%
    cardGaragePortail:
      - width: 24%
      - position: absolute
      - left: 25.6%
      - top: 4%
    cardPortail:
      - width: 24%
      - position: absolute
      - right: 25.6%
      - top: 4%
    cardGarage:
      - width: 24%
      - position: absolute
      - right: 0.8%
      - top: 4%

Le code de mon script unique pour armer/désarmer l’alarme :

sequence:
  - choose:
      - conditions:
          - condition: state
            entity_id: alarm_control_panel.alarme_maison
            state: disarmed
        sequence:
          - action: alarm_control_panel.alarm_arm_away
            metadata: {}
            data: {}
            target:
              entity_id: alarm_control_panel.alarme_maison
      - conditions:
          - condition: not
            conditions:
              - condition: state
                entity_id: alarm_control_panel.alarme_maison
                state: disarmed
        sequence:
          - action: alarm_control_panel.alarm_disarm
            metadata: {}
            data:
              code: "xxxxxxxxx"
            target:
              entity_id: alarm_control_panel.alarme_maison
alias: Alarme Maison
description: ""

Le code de mon automatisation:

alias: Auto_Alarme
description: Armer l'alarme si absence ou désarmer si présence.
triggers:
  - entity_id: person.serurier_matthieu
    from: home
    to: not_home
    trigger: state
  - entity_id: person.serurier_matthieu
    from: not_home
    to: home
    trigger: state
  - entity_id: person.tom
    from: home
    to: not_home
    trigger: state
  - entity_id: person.tom
    from: not_home
    to: home
    trigger: state
conditions: []
actions:
  - choose:
      - conditions:
          - condition: or
            conditions:
              - condition: state
                entity_id: person.serurier_matthieu
                state: home
              - condition: state
                entity_id: person.tom
                state: home
          - condition: state
            entity_id: alarm_control_panel.alarme_maison
            state: armed_away
        sequence:
          - device_id: f9bedac23d97acee2dd8819afa5e4ad6
            domain: alarm_control_panel
            entity_id: cd990de7edddaab308cbe195645649ac
            type: disarm
            code: "xxxxxxxx"
      - conditions:
          - condition: and
            conditions:
              - condition: state
                entity_id: alarm_control_panel.alarme_maison
                state: disarmed
              - condition: not
                conditions:
                  - condition: state
                    entity_id: person.serurier_matthieu
                    state: home
              - condition: not
                conditions:
                  - condition: state
                    entity_id: person.tom
                    state: home
        sequence:
          - device_id: f9bedac23d97acee2dd8819afa5e4ad6
            domain: alarm_control_panel
            entity_id: cd990de7edddaab308cbe195645649ac
            type: arm_away
mode: queued
1 « J'aime »

Le résultat est convaincant !

Oui pour le script le bloc de construction choisir est plus « puissant » que le « Si/alors » et s’il te permet d’éviter des bugs alors tant mieux !

PS: tu as laissé le code de l’alarme visible dans ton script, n’hésite pas à éditer ton message pour le masquer.

Merci @Integra
Oui, je suis très content.
Et je viens de masquer mon code, merci :slightly_smiling_face: