# \[Tuto\] Notification prioritaire sur Signal, et Fallback (Telegram/Matrix/Discord) si hors-ligne

**URL:** <https://forum.hacf.fr/t/tuto-notification-prioritaire-sur-signal-et-fallback-telegram-matrix-discord-si-hors-ligne/82458>\
**Category:** Automatisation / Scène / Script / BluePrint\
**Created:** [Août 1, 2026, 11:17 UTC](https://forum.hacf.fr/t/tuto-notification-prioritaire-sur-signal-et-fallback-telegram-matrix-discord-si-hors-ligne/82458 "2026-08-01T11:17:44Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![freetronic](https://forum.hacf.fr/user_avatar/forum.hacf.fr/freetronic/32/88342_2.png) [@freetronic](https://forum.hacf.fr/u/freetronic)\
**Post date:** [Août 1, 2026, 11:17 UTC](https://forum.hacf.fr/t/tuto-notification-prioritaire-sur-signal-et-fallback-telegram-matrix-discord-si-hors-ligne/82458/1 "2026-08-01T11:17:45Z")

</div>

Hello,

Je vous partage aujourd'hui un concept d'automatisation pour mettre en place des notifications en cascade avec acquittement automatique (système de Fallback).

L'idée est simple : lorsqu'un événement important se produit (ouverture d'une boîte aux lettres, alarme, etc.), Home Assistant envoie une notification sur un canal prioritaire et sécurisé (Signal). Si vous ne recevez pas ou ne lisez pas le message dans un délai imparti (par exemple, si votre téléphone est hors-ligne ou en mode avion), Home Assistant bascule automatiquement sur des canaux de secours (ex: Matrix, Telegram, Discord). Accessoirement on envoie pas de messages inutiles.. en doublon, triplon voir plus si affinité

📖 Un peu de vocabulaire :  
Fallback : C'est la bascule automatique vers une solution de secours (le "Plan B") lorsque le système principal échoue ou n'est pas disponible , on parle donc bien d'un mécanisme de Fallback (secours de notification).

 ![image](https://forum.hacf.fr/uploads/default/original/3X/3/7/377ad3a4b18eda2b557a658de81eab2c83e7d844.png)

🛠 Prérequis  
Pour réaliser ce tutoriel, vous aurez besoin de :

L'Add-on Signal Messenger REST API (de haberda/hassio\_addons ou similaire) configuré en mode json-rpc (obligatoire pour avoir les événements en temps réel).  
L'intégration HACS Signal Messenger WebSocket (de mattleh/signal\_websocket) pour capter les événements et accusés de réception.  
Avoir relié votre numéro Signal à l'Add-on.

👥 Étape 1 : Créer un groupe privé Signal (Pour les accusés automatiques)  
Pour que votre téléphone envoie un accusé de réception automatique dès que le message s'affiche sur votre écran (sans que vous ayez besoin d'ouvrir l'application) :

Créez un groupe dans l'application Signal sur votre téléphone.  
Ajoutez un contact temporaire (obligatoire pour créer un groupe dans Signal), nommez le groupe (ex: HA Notifications), puis retirez le contact temporaire. Vous êtes désormais seul dans ce groupe.  
Envoyez un message (ex: "test") dans ce groupe.  
Dans Home Assistant, allez dans Outils de développement ➔ Événements ➔ Écoutez l'événement signal\_received pour attraper l'événement. Vous y trouverez l'identifiant officiel du groupe (qui ressemble à : group.xxxxx...=).

🤖 L'automatisation simplifiée (Modèle à copier-coller)  
Voici une version générique et simplifiée de l'automatisation. Elle utilise un capteur de mouvement pour déclencher une prise de photo par une caméra, puis gère l'envoi intelligent :

> **Dépliez pour voir l'Automation**
>
> ```auto
> alias: Notification événement avec Fallback Signal
> description: Envoi prioritaire sur Signal, avec bascule après 60s vers d'autres canaux
> trigger:
> - platform: state
> entity_id: binary_sensor.votre_capteur # 1. Votre capteur ici
> from: "off"
> to: "on"
> variables:
> # --- Vos variables de chemin et d'entités ---
> camera_entity: camera.votre_camera # 2. Votre caméra ici
> photo_path: /config/www/alerte.jpg # Chemin de sauvegarde de l'image
> signal_group_id: "group.votre_identifiant_de_groupe_signal" # 3. Votre identifiant de groupe ici
> signal_received_confirmed: false
> action:
> # 1. Prise de photo (Snapshot)
> - action: camera.snapshot
> target:
> entity_id: "{{ camera_entity }}"
> data:
> filename: "{{ photo_path }}"
> # =========================================================
> # ÉTAPE 1 : ENVOI SUR SIGNAL
> # =========================================================
> # On sépare le texte de l'image pour éviter que le texte ne se retrouve coincé sous l'image dans l'application
>   
> # A. Envoi du texte explicatif
> - action: signal_websocket.send_message
> continue_on_error: true # <--- SÉCURITÉ : Passe à la suite si Signal est HS
> data:
> number: "+336XXXXXXXX" # Votre numéro expéditeur relié à l'Add-on
> group_id: "{{ signal_group_id }}"
> message: "✉️ Mouvement détecté sur la caméra !"
> # B. Envoi de l'image dans une bulle séparée
> - action: signal_websocket.send_message
> data:
> number: "+336XXXXXXXX"
> group_id: "{{ signal_group_id }}"
> message: ""
> attachments:
> - "{{ photo_path }}"
> # =========================================================
> # ÉTAPE 2 : ATTENTE ACQUITTEMENT (60 SECONDES MAX)
> # =========================================================
> # On boucle 12 fois (5 secondes par boucle) pour écouter le WebSocket.
> # Dès qu'un accusé de lecture (readMessages) ou de réception (isDelivery: true) arrive, on valide.
> - repeat:
> count: 12
> sequence:
> - if:
> - condition: template
> value_template: "{{ not signal_received_confirmed }}"
> then:
> - wait_for_trigger:
> - trigger: event
> event_type: signal_received
> timeout: "00:00:05"
> continue_on_timeout: true
> - if:
> - condition: template
> value_template: >-
> {% if wait.trigger is not none %}
> {# Détection de la lecture (Note à moi-même / Groupe) #}
> {% set is_read = wait.trigger.event.data.envelope.syncMessage is defined and wait.trigger.event.data.envelope.syncMessage.readMessages is defined %}
> {# Détection de la réception automatique #}
> {% set is_delivered = wait.trigger.event.data.envelope.receiptMessage is defined and wait.trigger.event.data.envelope.receiptMessage.isDelivery == true %}
> {{ is_read or is_delivered }}
> {% else %}
> false
> {% endif %}
> then:
> - variables:
> signal_received_confirmed: true
> # =========================================================
> # ÉTAPE 3 : ARRÊT DE L'AUTOMATISATION SI REÇU SUR SIGNAL
> # =========================================================
> - if:
> - condition: template
> value_template: "{{ signal_received_confirmed }}"
> then:
> - stop: "Message reçu sur Signal. Cascade annulée."
> # =========================================================
> # ÉTAPE 4 : CANAUX DE SECOURS (FALLBACK)
> # =========================================================
> # Si on arrive ici, c'est que les 60 secondes se sont écoulées sans accusé de réception sur Signal.
> # On envoie alors aux autres applications en parallèle.
> - parallel:
> # A. Secours Telegram
> - sequence:
> - action: telegram_bot.send_message
> data:
> message: "✉️ Mouvement détecté (Bascule secours) !"
> - action: telegram_bot.send_photo
> data:
> file: "{{ photo_path }}"
>               
> # B. Secours Discord
> - action: notify.votre_notificateur_discord
> data:
> message: "✉️ Mouvement détecté (Bascule secours) !"
> target:
> - "votre_id_de_salon_discord" # 4. Votre ID de canal Discord ici
> data:
> images:
> - "{{ photo_path }}"
>               
> # C. Secours Matrix
> - action: matrix.send_message
> data:
> target: "!votre_salon:matrix.org"
> message: "<b>✉️ Mouvement détecté (Bascule secours) !</b>"
> format: html
> data:
> images:
> - "{{ photo_path }}"
> mode: single
> 
> ```

💡 Comment ça réagit en pratique ?  
Si votre téléphone est connecté (Normal) : Dès que la notification s'affiche ou que vous lisez le message sur Signal, HA capte l'accusé de réception via le WebSocket, l'automatisation s'arrête d'elle-même au prochain cycle de 5 secondes, et vos comptes Matrix/Telegram/Discord restent silencieux.  
Si vous êtes hors-ligne (Mode avion / Perte réseau) : Votre téléphone ne renvoie aucun accusé. Au bout de 60 secondes, la boucle d'attente expire et HA envoie immédiatement l'alerte sur Matrix et/ou Discord et/ou Telegram.

Vous n'êtes bien évidement pas obligé de les utiliser tous, je suis en pleine migration et j'ai donc les 3 à disposition.

Avec un poil de complexité qui me caractérise 😃 , on arrive sur ça, on voit bien que les 3 notifs du bas sont ignorées.

 ![image](https://forum.hacf.fr/uploads/default/original/3X/7/d/7d300fde3c911e05505e70cd9ba58d31979bac6b.png)

alors qu'au contraire ( j'avais désactivé matrix pour ce test )

 ![image](https://forum.hacf.fr/uploads/default/original/3X/3/9/397f620d1f3a575333dc67c2e61bb087e364a94c.png)

Dans tous les cas signal étant la notification prioritaire, vous recevrez la notification dessus au retour de la connexion.

Edit: j'ajoute la version script ( non testée en simplifiée )

> **script**
>
> ```auto
> alias: "Notification cascade securise messageries"
> description: "Envoi prioritaire Signal et secours (Matrix/Telegram/Discord) avec détection de réception"
> fields:
> message_title:
> name: "Titre du message"
> description: "Le titre court ou l'entête de l'alerte"
> example: "✉️ Boite lettres ouverte"
> required: true
> url_local:
> name: "URL Locale"
> description: "Lien réseau local (optionnel)"
> example: "http://IP_LOCALE_FRIGATE:5000/review?cameras=NOM_CAMERA"
> required: false
> url_zt:
> name: "URL ZeroTier"
> description: "Lien à distance ZeroTier (optionnel)"
> example: "http://IP_ZEROTIER_FRIGATE:5000/review?cameras=NOM_CAMERA"
> required: false
> attachment:
> name: "Pièce jointe"
> description: "Chemin complet vers la photo/vidéo (optionnel)"
> example: "/dev/shm/courrier_alerte.jpg"
> required: false
> sequence:
> - variables:
> signal_received_confirmed: false
> 
> # 1. SIGNAL - Envoi du texte
> - action: signal_websocket.send_message
> continue_on_error: true
> data:
> number: "+336XXXXXXXX"
> group_id: "group.votre_id_de_groupe_signal_ici"
> message: >-
> {{ message_title }} ({{ now().strftime('%Hh%M') }})
> {% if url_local is defined and url_local %}
>           
> Local : {{ url_local }}
> {% endif %}
> {% if url_zt is defined and url_zt %}
>           
> ZeroTier : {{ url_zt }}
> {% endif %}
> 
> # 2. SIGNAL - Envoi de l'image (si présente)
> - if:
> - condition: template
> value_template: "{{ attachment is defined and attachment != '' }}"
> then:
> - action: signal_websocket.send_message
> continue_on_error: true
> data:
> number: "+336XXXXXXXX"
> group_id: "group.votre_id_de_groupe_signal_ici"
> message: ""
> attachments:
> - "{{ attachment }}"
> 
> # 3. Attente acquittement (60 secondes max)
> - repeat:
> count: 12
> sequence:
> - if:
> - condition: template
> value_template: "{{ not signal_received_confirmed }}"
> then:
> - wait_for_trigger:
> - trigger: event
> event_type: signal_received
> timeout: "00:00:05"
> continue_on_timeout: true
> - if:
> - condition: template
> value_template: >-
> {% if wait.trigger is not none %}
> {% set is_read = wait.trigger.event.data.envelope.syncMessage is defined and wait.trigger.event.data.envelope.syncMessage.readMessages is defined %}
> {% set is_delivered = wait.trigger.event.data.envelope.receiptMessage is defined and wait.trigger.event.data.envelope.receiptMessage.isDelivery == true %}
> {{ is_read or is_delivered }}
> {% else %}
> false
> {% endif %}
> then:
> - variables:
> signal_received_confirmed: true
> 
> # 4. Arrêt si reçu
> - if:
> - condition: template
> value_template: "{{ signal_received_confirmed }}"
> then:
> - stop: "Message reçu sur Signal. Cascade annulée."
> 
> # 5. Secours en parallèle
> - parallel:
> # A. Telegram
> - sequence:
> - action: telegram_bot.send_message
> data:
> parse_mode: html
> message: >-
> <b>{{ message_title }}</b> ({{ now().strftime('%Hh%M') }})
> {% if url_local is defined and url_local or url_zt is defined and url_zt %}
> 🔗 {% if url_local is defined and url_local %}<a href="{{ url_local }}">🏠 Local</a>{% endif %}{% if url_local is defined and url_local and url_zt is defined and url_zt %} | {% endif %}{% if url_zt is defined and url_zt %}<a href="{{ url_zt }}">🌍 ZeroTier</a>{% endif %}
> {% endif %}
> - if:
> - condition: template
> value_template: "{{ attachment is defined and attachment != '' }}"
> then:
> - action: telegram_bot.send_photo
> data:
> authentication: digest
> file: "{{ attachment }}"
> 
> # B. Discord
> - action: notify.freetronichabot
> data:
> message: ""
> target:
> - "votre_id_de_salon_discord"
> data:
> images: >-
> {{ [attachment] if (attachment is defined and attachment != '') else [] }}
> embed:
> title: "{{ message_title }} ({{ now().strftime('%Hh%M') }})"
> description: |
> {% if url_local is defined and url_local %}[🏠 Local](<{{ url_local }}>){% endif %}{% if url_local is defined and url_local and url_zt is defined and url_zt %} — {% endif %}{% if url_zt is defined and url_zt %}[🌍 ZeroTier](<{{ url_zt }}>){% endif %}
> color: 3447003
> image:
> url: "{{ 'attachment://' + attachment.split('/')[-1] if (attachment is defined and attachment != '') else '' }}"
> 
> # C. Matrix
> - action: matrix.send_message
> data:
> target: "!votre_salon:matrix.org"
> message: >-
> <b>{{ message_title }}</b> ({{ now().strftime('%Hh%M') }})
> {% if url_local is defined and url_local %}<a href="{{ url_local }}">🏠 Local</a>{% endif %}{% if url_local is defined and url_local and url_zt is defined and url_zt %} | {% endif %}{% if url_zt is defined and url_zt %}<a href="{{ url_zt }}">🌍 ZeroTier</a>{% endif %}
> format: html
> data: >-
> {{ {'images': [attachment]} if (attachment is defined and attachment != '') else {} }}
> 
> ```

> **automation allant avec le script**
>
> ```auto
> alias: alias: Surveillance courrier v4 avec script (Simplifiée)
> description: Notification courrier avec appel du script de cascade
> triggers:
> - trigger: state
> entity_id: binary_sensor.mvt_courrier_occupancy
> from: "off"
> to: "on"
> actions:
> # (Prise de photo locale, TTS, etc.)
> - action: camera.snapshot
> target:
> entity_id: camera.sonette
> data:
> filename: /dev/shm/courrier_alerte.jpg
> # Appel simple du script de cascade avec les données de l'événement
> - action: script.Notification_cascade_securise_messageries
> data:
> message_title: "✉️ Boite lettres ouverte"
> url_local: "http://IP_LOCALE_FRIGATE:5000/review?cameras=NOM_CAMERA"
> url_zt: "http://IP_ZEROTIER_FRIGATE:5000/review?cameras=NOM_CAMERA"
> attachment: "/dev/shm/courrier_alerte.jpg"
> mode: single
> 
> ```

cdt

---

<div class="post-metadata">

**Author:** ![bastgau](https://forum.hacf.fr/user_avatar/forum.hacf.fr/bastgau/32/46175_2.png) [@bastgau](https://forum.hacf.fr/u/bastgau)\
**Post date:** [Août 1, 2026, 11:35 UTC](https://forum.hacf.fr/t/tuto-notification-prioritaire-sur-signal-et-fallback-telegram-matrix-discord-si-hors-ligne/82458/2 "2026-08-01T11:35:58Z")

</div>

L'utilisation d'un script permettrait de ne pas le reproduire dans toutes les automatisations.

---

<div class="post-metadata">

**Author:** ![freetronic](https://forum.hacf.fr/user_avatar/forum.hacf.fr/freetronic/32/88342_2.png) [@freetronic](https://forum.hacf.fr/u/freetronic)\
**Post date:** [Août 1, 2026, 11:40 UTC](https://forum.hacf.fr/t/tuto-notification-prioritaire-sur-signal-et-fallback-telegram-matrix-discord-si-hors-ligne/82458/3 "2026-08-01T11:40:38Z")

</div>

Oui sans doute, à chacun d'adapter, je met la base pour s'assurer du bon fonctionnement 🙂
