[Article] Notifications dynamiques en fonction de la pièce occupée

Bonjour,
Merci pour l’idée, j’avoue que j’ai au préalable jouer un son FX avant :

target:
  entity_id:
    - media_player.florent_echo_studio_bignid
    - media_player.echo_cuisine_bignid
    - media_player.echo_salon_bignid
    - media_player.echo_dot_4_salle_de_bain_bignid
data:
  media_content_type: sound
  media_content_id: amzn_sfx_trumpet_bugle_04
action: media_player.play_media

Mais j’avoue que jouer le son plus fort me plait bien…

Si vous voulez tester d’autres sons, c’est ici sur le site d’Amazon et ici sur GitHub.

Et pour les impatients :

Bells and Buzzer

  • bells: “bell_02”

  • buzzer: “buzzers_pistols_01”

  • church_bell: “amzn_sfx_church_bell_1x_02”

  • doorbell1: “amzn_sfx_doorbell_01”

  • doorbell2: “amzn_sfx_doorbell_chime_01”

  • doorbell3: “amzn_sfx_doorbell_chime_02”

Holidays

  • xmas_bells: “christmas_05”

  • halloween_door: “horror_10”

Misc

  • air_horn: “air_horn_03”

  • boing1: “boing_01”

  • boing2: “boing_03”

  • camera: “camera_01”

  • squeaky_door: “squeaky_12”

  • ticking_clock: “clock_01”

  • trumpet: “amzn_sfx_trumpet_bugle_04”

Animals

  • cat_meow: “amzn_sfx_cat_meow_1x_01”

  • dog_bark: “amzn_sfx_dog_med_bark_1x_02”

  • lion_roar: “amzn_sfx_lion_roar_02”

  • rooster: “amzn_sfx_rooster_crow_01”

  • wolf_howl: “amzn_sfx_wolf_howl_02”

Scifi

  • aircraft: “futuristic_10”

  • engines: “amzn_sfx_scifi_engines_on_02”

  • red_alert: “amzn_sfx_scifi_alarm_04”

  • shields: “amzn_sfx_scifi_sheilds_up_01”

  • sirens: “amzn_sfx_scifi_alarm_01”

  • zap: “zap_01”

Crowds

  • applause: “amzn_sfx_crowd_applause_01”

  • cheer: “amzn_sfx_large_crowd_cheer_01”

Re,

Le diffuseur contextuel de l’article passe en V2 ici, avec @gael on a pas mal cherché de solutions pour surveiller les ouvrants ouverts et qui par oublie ou inattention, restent ouverts. J’ai fini par trouver une méthode simple en ajoutant 2 helper de surveillance des ouvrants extérieurs ( une seconde version verra le jour pour la surveillance des congélo et autres frigo qui nécessitent un temps de réaction plus court. mais posons les bases).

j’ai donc commencé par ajouter 2 helper liste et nombre d’ouvrants ( que je liste, parce que c’est plus simple à maintenir comme ça pour moi. Tout ça pour ajouter un bouton qui me signale les ouvrants ouverts et leur nombre.

Liste_ouvrants
{{ expand([
  'binary_sensor.porte1_salon_2',
  'binary_sensor.porte2_salon_2',
  'binary_sensor.porte_entree_2',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre1_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre2_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre3_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_porte1_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_porte2_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre4_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre5_veranda',
  'binary_sensor.olimex_esp32_poe_veranda_fenetre6_veranda',
  'binary_sensor.olimex_esp32_poe_garagext_porte1_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_porte2_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_porte3_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_porte4_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_fenetre1_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_fenetre2_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_fenetre3_garagext',
  'binary_sensor.olimex_esp32_poe_garagext_fenetre4_garagext',
  'binary_sensor.olimex_esp32_poe_etage_fd_amis',
  'binary_sensor.olimex_esp32_poe_etage_fg_amis',
  'binary_sensor.olimex_esp32_poe_etage_fg_sdb',
  'binary_sensor.olimex_esp32_poe_etage_fd_sdb',
  'binary_sensor.olimex_esp32_poe_etage_fd_laurent',
  'binary_sensor.olimex_esp32_poe_etage_fg_laurent',
  'binary_sensor.olimex_esp32_poe_etage_fg_papa',
  'binary_sensor.olimex_esp32_poe_etage_fd_papa'
]) | selectattr('state', 'eq', 'on') | map(attribute='name') | list | join(', ') }}
nombre_ouvrants
{{ [
  states('binary_sensor.porte1_salon_2'),
  states('binary_sensor.porte2_salon_2'),
  states('binary_sensor.porte_entree_2'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre1_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre2_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre3_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_porte1_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_porte2_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre4_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre5_veranda'),
  states('binary_sensor.olimex_esp32_poe_veranda_fenetre6_veranda'),
  states('binary_sensor.olimex_esp32_poe_garagext_porte1_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_porte2_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_porte3_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_porte4_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_fenetre1_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_fenetre2_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_fenetre3_garagext'),
  states('binary_sensor.olimex_esp32_poe_garagext_fenetre4_garagext'),
  states('binary_sensor.olimex_esp32_poe_etage_fd_amis'),
  states('binary_sensor.olimex_esp32_poe_etage_fg_amis'),
  states('binary_sensor.olimex_esp32_poe_etage_fg_sdb'),
  states('binary_sensor.olimex_esp32_poe_etage_fd_sdb'),
  states('binary_sensor.olimex_esp32_poe_etage_fd_laurent'),
  states('binary_sensor.olimex_esp32_poe_etage_fg_laurent'),
  states('binary_sensor.olimex_esp32_poe_etage_fg_papa'),
  states('binary_sensor.olimex_esp32_poe_etage_fd_papa')
] | select('eq', 'on') | list | count }}

Et là… le déclic

image

On obtient une liste, pourquoi ne pas la diffuser tant qu’un de ces ouvrants restent ouverts?

automation de surveillance de portes restées ouvertes
alias: TTS - Alerte Ouvrant reste ouvert 5 min
description: >-
  Envoie un message initial après 5 min, puis le répète toutes les 5 min tant
  qu'un ouvrant est ouvert.
triggers:
  - entity_id: sensor.nombre_ouvrants
    above: 0
    for: "00:05:00"
    trigger: numeric_state
conditions:
  - condition: numeric_state
    entity_id: sensor.nombre_ouvrants
    above: 0
actions:
  - repeat:
      while:
        - condition: numeric_state
          entity_id: sensor.nombre_ouvrants
          above: 0
      sequence:
        - target:
            entity_id: automation.tts_diffuseur_contextuel
          data:
            skip_condition: true
            variables:
              message: >-
                Attention, les ouvrants suivants sont toujours ouverts : {{
                states('sensor.liste_ouvrants') }}
          action: automation.trigger
        - delay: "00:05:00"
mode: single

I. Section « Triggers » (Déclencheurs) :hourglass_not_done:

Le but ici est d’attendre 5 minutes complètes avant de lancer la séquence d’alerte.

triggers:
  - entity_id: sensor.nombre_ouvrants
    above: 0
    for: "00:05:00"
    trigger: numeric_state
  • entity_id: sensor.nombre_ouvrants: Cible votre Helper qui compte le nombre d’ouvrants ouverts.
  • above: 0: La condition est remplie si le nombre d’ouvrants ouverts est strictement supérieur à zéro (c’est-à-dire qu’au moins un ouvrant est ouvert).
  • for: "00:05:00": C’est le point clé. L’automatisation ne se déclenchera qu’une seule fois : au moment où l’entité sensor.nombre_ouvrants a maintenu une valeur > 0 pendant 5 minutes consécutives.

II. Section « Conditions » (Vérification) :white_check_mark:

Cette section est une vérification de sécurité qui garantit que l’alerte n’est pas lancée si la porte vient d’être fermée juste après le délai de 5 minutes.

conditions:
  - condition: numeric_state
    entity_id: sensor.nombre_ouvrants
    above: 0
  • On vérifie une dernière fois que le nombre d’ouvrants ouverts est toujours > 0 au moment où l’action va se lancer. Si une porte a été fermée à T+4:59, le déclencheur n’aurait pas fonctionné. Si la porte est fermée à T+5:01, cette condition empêche l’action.

III. Section « Actions » (La Boucle Répétitive) :repeat_button:

C’est ici que la logique de répétition conditionnelle est mise en place grâce au bloc repeat.

actions:
  - repeat:
      while:
        - condition: numeric_state
          entity_id: sensor.nombre_ouvrants
          above: 0
      sequence:
        # ... (Envoi du TTS)
        - delay: "00:05:00"

1. repeat: while (La Condition de Maintien)

  • while: Ce bloc définit la condition qui doit être vraie pour que la séquence d’actions (sequence) soit exécutée à nouveau.
  • condition: numeric_state / above: 0: Tant que le sensor.nombre_ouvrants est supérieur à zéro (donc au moins un ouvrant est ouvert), la boucle continue. Si cette condition devient fausse (tous les ouvrants sont fermés), la boucle s’arrête immédiatement.

2. sequence (Les Étapes de l’Alerte)

  • Envoi du Message TTS:
- target:
        entity_id: automation.tts_diffuseur_contextuel
      data:
        variables:
          message: >-
            Attention, les ouvrants suivants sont toujours ouverts : {{ states('sensor.liste_ouvrants') }}
      action: automation.trigger
  • On appelle le diffuseur contextuel ( on va y revenir, c’est le coeur du système ) TTS - Diffuseur contextuel en lui passant un message. Le message utilise le Helper de liste (sensor.liste_ouvrants) pour indiquer précisément quelles portes sont ouvertes.
  • Délai entre les Alertes:

- delay: "00:05:00"

Après avoir diffusé le message, l’automatisation marque une pause de 5 minutes. Une fois cette pause terminée, l’automatisation revient automatiquement vérifier la condition while pour décider de répéter l’alerte ou de s’arrêter.

IV. Section « Mode » (Gestion de l’Instance) :gear:

mode: single

mode: single: Ce mode garantit que l’automatisation ne peut pas se redéclencher tant que la première instance est en cours d’exécution (c’est-à-dire tant qu’elle est dans le delay de la boucle repeat). C’est le mode idéal ici, car il garantit que vous ne lancez qu’une seule boucle d’alerte, même si d’autres portes s’ouvrent pendant le délai. (à voir suivant votre utilisation).

On en vient au coeur du système détaillé dans l’article, le diffuseur contextuel.

Diffuseur contextuel V1
alias: TTS - Diffuseur contextuel
description: Diffuse un message dans les pièces où une présence est détectée
triggers:
  - event_type: dummy_startup_never_fired
    trigger: event
conditions:
  - condition: template
    value_template: "{{ occupied_rooms | length > 0 }}"
  - condition: template
    value_template: "{{ door_message is defined and door_message | length > 0 }}"
actions:
  - target:
      entity_id: "{{ occupied_rooms }}"
    data:
      volume_level: 0.8
    action: media_player.volume_set
  - delay: "00:00:01"
  - target:
      entity_id: tts.google_en_com
    data:
      cache: true
      media_player_entity_id: "{{ occupied_rooms }}"
      message: "{{ message }}"
      language: fr
    action: tts.speak
  - wait_template: "{{ is_state(occupied_rooms[0], 'playing') }}"
    timeout: "00:00:01"
  - wait_template: "{{ is_state(occupied_rooms[0], 'idle') }}"
    timeout: "00:00:05"
  - target:
      entity_id: "{{ occupied_rooms }}"
    data:
      volume_level: 0.5
    action: media_player.volume_set
mode: queued
variables:
  message: "{{ trigger.variables.message | default('') }}"
  occupied_rooms: >
    {% set rooms = [] %} {% if states('sensor.presence_entree') == 'Entree' %}{%
    set rooms = rooms + ['media_player.entree'] %}{% endif %} {% if
    states('sensor.presence_cagibi') == 'Cagibi' %}{% set rooms = rooms +
    ['media_player.entree'] %}{% endif %} {% if
    states('sensor.presence_cuisine') == 'Cuisine' %}{% set rooms = rooms +
    ['media_player.cuisine'] %}{% endif %} {% if
    states('sensor.presence_salle_manger') == 'Salle_manger' %}{% set rooms =
    rooms + ['media_player.salon'] %}{% endif %} {% if
    states('sensor.presence_chaufferie') == 'Chaufferie' %}{% set rooms = rooms
    + ['media_player.chaufferie'] %}{% endif %} {% if
    states('sensor.presence_labo') == 'Labo' %}{% set rooms = rooms +
    ['media_player.labo'] %}{% endif %} {% if
    states('sensor.presence_garage_interne') == 'Garage_interne' %}{% set rooms
    = rooms + ['media_player.garage_interne'] %}{% endif %} {% if
    states('sensor.presence_veranda') == 'Veranda' %}{% set rooms = rooms +
    ['media_player.veranda'] %}{% endif %} {% if states('sensor.presence_wc') ==
    'Wc' %}{% set rooms = rooms + ['media_player.toilettes'] %}{% endif %} {% if
    states('sensor.presence_chambre_laurent') == 'Chambre_laurent' %}{% set
    rooms = rooms + ['media_player.chambre_laurent'] %}{% endif %} {% if
    states('sensor.presence_chambre_papa') == 'Chambre_papa' %}{% set rooms =
    rooms + ['media_player.chambre_papa'] %}{% endif %} {% if
    states('sensor.presence_chambre_amis') == 'Chambre_amis' %}{% set rooms =
    rooms + ['media_player.chambre_amis'] %}{% endif %} {% if
    states('sensor.presence_sdb') == 'Sdb' %}{% set rooms = rooms +
    ['media_player.salle_de_bain'] %}{% endif %} {% if
    states('sensor.presence_garage_externe') == 'Garage_externe' %}{% set rooms
    = rooms + ['media_player.garage_externe'] %}{% endif %} {{ rooms | unique |
    list }}

j’avais quand même un soucis de taille, autant pour le reste tout fonctionne, autant pour la surveillance de ouvrants et je pense que c’est un soucis de longueur de message, le diffuseur montait bien le volume, puis le baissait avant de le diffuser sur la/les borne(s) de la ou des pièces occupées.

sur une idée originale de @Gael, on passe donc de ça

  - wait_template: "{{ is_state(occupied_rooms[0], 'playing') }}"
    timeout: "00:00:01"
  - wait_template: "{{ is_state(occupied_rooms[0], 'idle') }}"
    timeout: "00:00:05"

à ça

  - variables:
      calculated_delay: "{{ ((message | length / 12) + 3) | round(0) }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: "{{ calculated_delay | int }}"
      milliseconds: 0

La nouvelle méthode utilise la longueur du message (message | length) pour estimer de manière dynamique le temps de lecture, ajoutant une marge de sécurité.

calculated_delay: "{{ ((message | length / 12) + 3) | round(0) }}"

  • message | length / 12: On divise la longueur totale du message (nombre de caractères) par une estimation du taux de parole (environ 12 caractères par seconde). Cela donne une bonne approximation de la durée de lecture.

  • 3: On ajoute 3 secondes de marge de sécurité. Ces secondes sont essentielles pour couvrir la latence du réseau, le temps de chargement du fichier TTS sur l’appareil Cast, et le temps de transition.

| round(0): On arrondit le résultat à la seconde près.


- variables:
      calculated_delay: ...
  - delay:
      seconds: "{{ calculated_delay | int }}"

Il est essentiel d’expliquer pourquoi la méthode d’attente a été changée. La nouvelle méthode basée sur un délai calculé dynamiquement est bien plus robuste pour la diffusion TTS sur des appareils Cast (Google Home).

:face_with_monocle: Pourquoi Changer le Mécanisme d’Attente ?

Le problème principal des notifications TTS (Text-to-Speech) est d’assurer que le système attend la fin complète de la lecture avant d’exécuter l’action suivante (dans notre cas, baisser le volume à 0.5).

L’ancienne méthode, utilisant wait_template sur les états playing et idle, est souvent unreliable pour les raisons suivantes :

  1. Problèmes de l’Ancienne Méthode (wait_template) :cross_mark:

Problème Explication
Latence Le service TTS (Google, Amazon) prend quelques secondes pour générer le fichier audio, le charger et le lire. Le timeout de 5 secondes pour attendre l’état idle (inactivité) est trop court si le message est long (comme une liste de portes ouvertes).
États Capricieux Les appareils Cast ne changent pas toujours d’état rapidement ou de manière fiable entre playing et idle. L’état peut rester sur playing même après la fin du message ou passer trop tôt à idle.
Timeout Fixe Si un message prend 15 secondes à lire, le timeout de 5 secondes ne sera pas suffisant, et le script baissera le volume pendant la lecture, coupant le message.

  1. Avantages de la Nouvelle Méthode (Délai Calculé) :white_check_mark:

La nouvelle méthode utilise la longueur du message (message | length) pour estimer de manière dynamique le temps de lecture, ajoutant une marge de sécurité.

A. Le Calcul Dynamique

calculated_delay: "{{ ((message | length / 12) + 3) | round(0) }}"

message | length / 12: On divise la longueur totale du message (nombre de caractères) par une estimation du taux de parole (environ 12 caractères par seconde). Cela donne une bonne approximation de la durée de lecture.

+ 3: On ajoute 3 secondes de marge de sécurité. Ces secondes sont essentielles pour couvrir la latence du réseau, le temps de chargement du fichier TTS sur l'appareil Cast, et le temps de transition.

| round(0): On arrondit le résultat à la seconde près.

B. La Mise en Œuvre dans l’Action

  - variables:
      calculated_delay: ...
  - delay:
      seconds: "{{ calculated_delay | int }}"

En remplaçant le wait_template fixe par un delay basé sur ce calcul :

Fiabilité Accrue : L’automatisation attendra juste assez longtemps pour que même les messages longs (comme la liste des ouvrants ouverts) aient le temps d’être complètement diffusés.

Performance Optimale : Dès que le temps calculé est écoulé, le volume est baissé sans attendre un état hypothétique, et le script ne reste pas bloqué inutilement.

En résumé, on passe d’une attente basée sur un état incertain et un temps fixe à une attente basée sur une estimation de la durée réelle du contenu.

le code complet du diffuseur contextuel V2
alias: TTS - Diffuseur contextuel
description: Diffuse un message dans les pièces où une présence est détectée
triggers:
  - event_type: dummy_startup_never_fired
    trigger: event
conditions:
  - condition: template
    value_template: "{{ occupied_rooms | length > 0 }}"
  - condition: template
    value_template: "{{ door_message is defined and door_message | length > 0 }}"
actions:
  - target:
      entity_id: "{{ occupied_rooms }}"
    data:
      volume_level: 0.8
    action: media_player.volume_set
  - delay: "00:00:01"
  - target:
      entity_id: tts.google_en_com
    data:
      cache: true
      media_player_entity_id: "{{ occupied_rooms }}"
      message: "{{ message }}"
      language: fr
    action: tts.speak
  - variables:
      calculated_delay: "{{ ((message | length / 12) + 3) | round(0) }}"
  - delay:
      hours: 0
      minutes: 0
      seconds: "{{ calculated_delay | int }}"
      milliseconds: 0
  - target:
      entity_id: "{{ occupied_rooms }}"
    data:
      volume_level: 0.5
    action: media_player.volume_set
mode: queued
variables:
  message: "{{ trigger.variables.message | default('') }}"
  occupied_rooms: >
    {% set rooms = [] %} {% if states('sensor.presence_entree') == 'Entree' %}{%
    set rooms = rooms + ['media_player.entree'] %}{% endif %} {% if
    states('sensor.presence_cagibi') == 'Cagibi' %}{% set rooms = rooms +
    ['media_player.entree'] %}{% endif %} {% if
    states('sensor.presence_cuisine') == 'Cuisine' %}{% set rooms = rooms +
    ['media_player.cuisine'] %}{% endif %} {% if
    states('sensor.presence_salle_manger') == 'Salle_manger' %}{% set rooms =
    rooms + ['media_player.salon'] %}{% endif %} {% if
    states('sensor.presence_chaufferie') == 'Chaufferie' %}{% set rooms = rooms
    + ['media_player.chaufferie'] %}{% endif %} {% if
    states('sensor.presence_labo') == 'Labo' %}{% set rooms = rooms +
    ['media_player.labo'] %}{% endif %} {% if
    states('sensor.presence_garage_interne') == 'Garage_interne' %}{% set rooms
    = rooms + ['media_player.garage_interne'] %}{% endif %} {% if
    states('sensor.presence_veranda') == 'Veranda' %}{% set rooms = rooms +
    ['media_player.veranda'] %}{% endif %} {% if states('sensor.presence_wc') ==
    'Wc' %}{% set rooms = rooms + ['media_player.toilettes'] %}{% endif %} {% if
    states('sensor.presence_chambre_laurent') == 'Chambre_laurent' %}{% set
    rooms = rooms + ['media_player.chambre_laurent'] %}{% endif %} {% if
    states('sensor.presence_chambre_papa') == 'Chambre_papa' %}{% set rooms =
    rooms + ['media_player.chambre_papa'] %}{% endif %} {% if
    states('sensor.presence_chambre_amis') == 'Chambre_amis' %}{% set rooms =
    rooms + ['media_player.chambre_amis'] %}{% endif %} {% if
    states('sensor.presence_sdb') == 'Sdb' %}{% set rooms = rooms +
    ['media_player.salle_de_bain'] %}{% endif %} {% if
    states('sensor.presence_garage_externe') == 'Garage_externe' %}{% set rooms
    = rooms + ['media_player.garage_externe'] %}{% endif %} {{ rooms | unique |
    list }}

On peut facilement envisager la surveillance de n’importe quoi sur un état que l’on ne sohaite pas. Ici ce sont les portes, j’ai réglé sur 5 minutes les répétitions, je vais également faire la même chose sur les portes congélateurs et frigo avec un temps de répétition plus court. Mais tout est envisageable.

Logs
Effectuer l'action « Automatisation: Déclencher » sur TTS - Diffuseur contextuel
Itération 1
Exécuté : 22 novembre 2025 à 10:19:25
Résultat :

params:
  domain: automation
  service: trigger
  service_data:
    skip_condition: true
    variables:
      message: >-
        Attention, les ouvrants suivants sont toujours ouverts : Porte2 garage
        exterieur, Porte1 garage exterieur
    entity_id:
      - automation.tts_diffuseur_contextuel
  target:
    entity_id:
      - automation.tts_diffuseur_contextuel
running_script: true

child_id:
  domain: automation
  item_id: '1751786922063'
  run_id: d650472aede808d36221aab53892647b

Effectuer l'action « Automatisation: Déclencher » sur TTS - Diffuseur contextuel
Itération 2
Exécuté : 22 novembre 2025 à 10:20:39
Résultat :

params:
  domain: automation
  service: trigger
  service_data:
    skip_condition: true
    variables:
      message: >-
        Attention, les ouvrants suivants sont toujours ouverts : Porte3 garage
        exterieur, Porte2 garage exterieur, Porte1 garage exterieur
    entity_id:
      - automation.tts_diffuseur_contextuel
  target:
    entity_id:
      - automation.tts_diffuseur_contextuel
running_script: true

child_id:
  domain: automation
  item_id: '1751786922063'
  run_id: b1367481b46acafe431f7dd9450a46e9

Effectuer l'action « Automatisation: Déclencher » sur TTS - Diffuseur contextuel
Itération 3
Exécuté : 22 novembre 2025 à 10:21:54
Résultat :

params:
  domain: automation
  service: trigger
  service_data:
    skip_condition: true
    variables:
      message: >-
        Attention, les ouvrants suivants sont toujours ouverts : Porte3 garage
        exterieur, Porte2 garage exterieur, Porte1 garage exterieur
    entity_id:
      - automation.tts_diffuseur_contextuel
  target:
    entity_id:
      - automation.tts_diffuseur_contextuel
running_script: true

child_id:
  domain: automation
  item_id: '1751786922063'
  run_id: c6438103faad68e3e2ce1b5a2ee56c54

Effectuer l'action « Automatisation: Déclencher » sur TTS - Diffuseur contextuel
Itération 4
Exécuté : 22 novembre 2025 à 10:23:09
Résultat :

params:
  domain: automation
  service: trigger
  service_data:
    skip_condition: true
    variables:
      message: >-
        Attention, les ouvrants suivants sont toujours ouverts : Porte3 garage
        exterieur, Porte2 garage exterieur, Porte1 garage exterieur
    entity_id:
      - automation.tts_diffuseur_contextuel
  target:
    entity_id:
      - automation.tts_diffuseur_contextuel
running_script: true

child_id:
  domain: automation
  item_id: '1751786922063'
  run_id: cb81fec9892cf7b0c7013f9888b6efc9

Effectuer l'action « Automatisation: Déclencher » sur TTS - Diffuseur contextuel
Itération 5
Exécuté : 22 novembre 2025 à 10:24:24
Résultat :

params:
  domain: automation
  service: trigger
  service_data:
    skip_condition: true
    variables:
      message: >-
        Attention, les ouvrants suivants sont toujours ouverts : Porte1 garage
        exterieur
    entity_id:
      - automation.tts_diffuseur_contextuel
  target:
    entity_id:
      - automation.tts_diffuseur_contextuel
running_script: true

child_id:
  domain: automation
  item_id: '1751786922063'
  run_id: ded2d22c638a6e3d1a63d8909614bac6

j’avais passé le timer à 1minute pour les tests

cdt

1 « J'aime »

Re,

La V3 du diffuseur contextuel est en approche, cette version, plus particulièrement pensée pour les ouvrants pourra être utilisée bien évidemment ailleurs

Etat des lieux avec La V2 actuelle

1 personne présente dans la cuisine
1 personne présente dans la salle de bain
1 personne présente dans l’entrée

La personne de l’entrée ouvre la porte entrée

« Porte entrée ouverte » joué sur gh entrée, gh cuisine, gh salle de bain

même cas de figure

1 personne présente dans la cuisine
1 personne présente dans la salle de bain
1 personne dehors ( donc pas présente dans l’entrée )

La personne dehors ouvre la porte entrée

« Porte entrée ouverte » joué sur gh cuisine, gh salle de bain

maintenant ce que va apporter la V3 en test c’est un exclude sur les ouvrants de la pièce concernée ( parce qu’à force c’est un brin pénible et que ça ne sert pas à grand chose qd on passe de l’intérieur vers l’extérieur ) toutes les transitions de l’intérieur vers l’extérieur ne sont plus diffusée sur la pièce concernée ( sisi c’est pénible qd ça tourne tout le temps ).

1 personne présente dans la cuisine
1 personne présente dans la salle de bain
1 personne présente dans l’entrée

La personne de l’entrée ouvre la porte entrée

« Porte entrée ouverte » joué sur gh cuisine, gh salle de bain, pas joué sur le gh entrée ( malgré la présence )

même cas de figure

1 personne présente dans la cuisine
1 personne présente dans la salle de bain
1 personne dehors ( donc pas présente dans l’entrée )

La personne dehors ouvre la porte entrée

« Porte entrée ouverte » joué sur gh cuisine, gh salle de bain

Les tests sont en cours et très prometteurs, de mon côté le diffuseur V2 va rester en prod sur les congelos et frigo pour l’instant ( ça serait stupide de ne pas diffuser dans la cuisine que le frigo est resté ouvert … ).

J’y reviendrait plus largement après les tests avec le code, quand tout sera validé.

un peu de grain à moudre :smiley:

variables:
  message: "{{ trigger.variables.message | default('') }}"
  trigger_entity_id: "{{ trigger.variables.trigger_entity_id | default('') }}"
  occupied_rooms: >
    {% set rooms = [] %}

    # Mapping entity_id -> media_player {% set room_map = {
      'entree': 'media_player.entree',
      'veranda': 'media_player.veranda',
      'garagext': 'media_player.garage_externe',
      'labo': 'media_player.labo',
      'chaufferie': 'media_player.chaufferie',
      'cave': 'media_player.veranda',
      'salon': 'media_player.salon',
      'laurent': 'media_player.chambre_laurent',
      'papa': 'media_player.chambre_papa',
      'amis': 'media_player.chambre_amis',
      'sdb': 'media_player.salle_de_bain'
    } %}

    # Identifier le player à exclure basé sur l'entity_id déclencheur {% set
    player_to_exclude = namespace(value='') %} {% for key, player in
    room_map.items() %}
      {% if key in trigger_entity_id.lower() %}
        {% set player_to_exclude.value = player %}
      {% endif %}
    {% endfor %}

    # Construire la liste des diffuseurs occupés en excluant le player
    déclencheur {% if states('sensor.presence_entree') == 'Entree' and
    'media_player.entree' != player_to_exclude.value %}
      {% set rooms = rooms + ['media_player.entree'] %}
    {% endif %}

    {% if states('sensor.presence_cagibi') == 'Cagibi' and 'media_player.entree'
    != player_to_exclude.value %}
      {% set rooms = rooms + ['media_player.entree'] %}
    {% endif %}

oui j’ai viré la V0 d’où le décalage dans la numérotation.

cdt

Personallement je fait comme ceci:

annonce des portes ouverte au bout de 30secondes d’ouverture avec une conditions qu’il y est une personne dans la maison. et ensuite va notifier les echo dot alexa par rapport au capteur de présence:

alias: Teste annonce porte entrée ouverte
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.magnet_porte_entree_opening
    from: "off"
    to: "on"
    for:
      hours: 0
      minutes: 0
      seconds: 30
conditions:
  - condition: template
    value_template: >-
      {{ expand('zone.home') | selectattr('state', 'eq', 'home') | list | count
      > 0 }}
actions:
  - action: notify.alexa_media
    metadata: {}
    data:
      target: |
        {% set echos = [
          iif(is_state('binary_sensor.detecteur_presence_bureau_presence', 'on'), 'media_player.echo_bureau', ''),
          iif(is_state('binary_sensor.detecteur_presence_chbr_parent_presence', 'on'), 'media_player.echo_parent', ''),
          iif(is_state('binary_sensor.detecteur_presence_salon_presence', 'on'), 'media_player.echo_salon', ''),
          iif(is_state('binary_sensor.detecteur_presence_chbr_lenzo_presence', 'on'), 'media_player.echo_tiago', '')
        ] %} {{ echos | reject('equalto', '') | list }}
      message: La porte d'entrée est ouverte depuis plus de 30 secondes
      data:
        type: announce
mode: single
1 « J'aime »

Faudrait en faire un script, ca serait plus souple :smiley:

1 « J'aime »