Check if scene (created on the fly) is created before activating it

I’m trying to set a scene up on the fly (snapshot entities):

service: scene.create
data:
  scene_id: master_sitting_before
  snapshot_entities: light.master_sitting_room

Then later in the automation (after doing some other things) I want to check if the scene was created, and if so delay 10 minutes then activate it to restore the light. I could just default to delaying 10 minutes, then activating, but I don’t want the automation sitting around that long if it isn’t needed, and I’d rather not create two separate automations for this.

I also considered using a variable instead of a scene, but wanted to see if I could do it “natively” first.

I tried using a template condition {{ states ('scene.master_sitting_before') is defined }}, but when I was testing it I found that everything returns true, for example: {{ states ('scene.zxczxghjrsdfsdfsdfsd') is defined }} is true.

Now that I think of it though - will this plan work at all? Once a scene is created on the fly, I assume it persists - so if I run it today and create the scene, then it runs a few hours later but does NOT snapshot the scene, I believe my current plan will fail and it will turn the on the fly scene on again anytime the automation runs.

So maybe my best option is to use a variable here…?

Someone else had a similar question and I demonstrated how to do it here:

The relevant part is this service call which calls the snapshot scene if it is defined otherwise it calls another scene.

      - service: scene.turn_on
        target:
          entity_id: >
            scene.{{ 'automated_office_state_lights' if states.scene.automated_office_state_lights.state is defined else 'office_working' }}
2 Likes

Incorrect. It does not persist. Scenes created via scene.create disapper when you restart HA or reload scenes from the GUI.

Note that I believe saving any scene in the GUI reloads all scenes in the background. Automations no longer do this (only the one you modified is reloaded) but I’m pretty sure scenes still do.

Right, this won’t work because of this:

The output of this is the string unknown. The defined tests checks if something exists and a string exists so that passes.

This is actually one of the very few cases where you want to ignore this warning in the templating doc:

It’s telling you to use those filters to ensure you don’t get an error when something doesn’t exist. But that’s what you want here, you want to test for existence. So you should use the technique its telling you to avoid like this:

{{ states.scene.master_sitting_before.state is defined }}
1 Like

Thanks to you both for the help.

This is a nice way to handle things if I wanted to always restore something, but, in this case I was trying to both add a delay and only restore a scene if I had created it earlier in the automation (in an if statement).

I could use this in the if statement:

{{ states.scene.master_sitting_before.state is defined }}

But as mentioned:

This was my WTH request (for automations), I was so happy to see it fulfilled. My pointing this out contributes nothing to this conversation though haha.

So anyway, checking if the scene exists still wouldn’t work well since if the automation runs now (and creates the scene), then again in an hour (and does NOT create the scene), the second time it runs, it will still see the scene as being defined and it will activate it, which is not what we want.

You’re combining two of my statements in a weird way.

Scenes created via scene.create disappear after an HA restart or a reload of scenes. This latter bit can happen anytime you save a scene in the GUI or if you click the reload scenes button.

It does not matter when or if automations reload. If an automation uses scene.create in step 1, has a 5 minute delay and then tries to reference that scene in step 5 it may not exist by step 5. Even if no automations are reloaded. Because when scenes are reloaded is entirely independent.

Counter point - you may have reloaded automations 1000 times and the scene you created in step 1 still exists. Because scenes never reloaded.

The comparison I was trying to make that saving any scene in the GUI reloads all scenes (and removes any created via scene.create). Whereas saving an automation in the GUI only reloads that automation.

1 Like

Sorry about that, I wasn’t trying to say anything related to automations reloading having any effect on scenes.

But, my point is just that the scene will still exist on subsequent runs of the automation (as you mentioned until scenes are reloaded).

Example pseudocode for an automation action:

if(whatever):
  save scene (X)
end if
do some other things

# part 2 (that I'm trying to figure out how to do):
if(scene X was saved in this automation)
  delay 10 minutes
  restore scene X
end if 

But this won’t work, since if this automation runs say, 5 times before scenes are reloaded, then after run 1, runs 2-5 will all run part 2 even if the if(whatever) isn’t true.

Ah. Yea ok we’re on the same page. If it needs to be specifically the scene created by that particular run of the automation then perhaps make the scene id in automation variable at the top and include a timestamp. Then you can check for it’s existence and have it be specific to that run.

Although it seemed like you were trying to avoid variables for some reason. Any reason for that or just didn’t want to make it longer unless necessary?

I’ll be honest, I forgot there was such a thing as “native” variables. I was thinking of the variables custom component, which I was trying to avoid if possible (just try to avoid extra dependencies).

Looking at the script documentation, which I believe applies to automations as well, it looks like variable scoping will not allow this to work though? Variable scope docs/example: Script Syntax - Home Assistant

Using my example from above:

set variable x_set = 0
if(whatever):
  save scene (X)
  set x_set = 1
end if
do some other things

# part 2 (that I'm trying to figure out how to do):
# here x_set will be 0 still because of scope.
if(scene X was saved in this automation)
  delay 10 minutes
  restore scene X
end if

Ah. That actually won’t work well. Since variables created by that integration are global you’d have the same problem. Run 1 of the automation sets the variable entity, run 2 of the automation sees that it is set but didn’t actually set it itself.

True, this won’t work due to scoping. This will:

set variable x = f"scene.my_scene_{now().timestamp}"
if(whatever)
  save scene(name=x, contents=whatever)
end if
do stuff...

if(scene with name x exists)
  scene.turn_on x
end if

Basically make the name you’ll use if you do save a scene at the top. Then you can use that variable throughout the automation.

Although I should note that this is a bit strange:

Generally you wouldn’t want the delay after you checked for existence of the scene. Kind of defeats the point of checking for existence, the scene may have existed before the delay and may not exist after.

Also it looks like you’re just checking to see if this automation saved a scene and want to use the same name every time in all runs of the automation. That seems bizarre to me since then each run automation will blow away the scenes created by other runs to save its own. If that truly is what you want though then you can just do this:

set variable to_save = whatever # Your condition from before
if(to_save)
  save scene(name="my_scene", contents=whatever)
end if
do stuff...

if(to_save)
  scene.turn_on my_scene
end if

Basically stuff “whatever” (your condition) in a variable and check it twice.

@123 or @CentralCommand
I have a question related to your solution.
What if the scene name is passed as a variable to the script?
Since this special state syntax doesn’t take parameters as it’s not a function call but an access of a “property”, I’m struggling to figure out how to parametrize it.
What I mean is the following – imagine that my_scene is coming from a param and I want the template to evaluate to true or false (it’s inside an if statement in my script)

Attempt 1 - as expected, this doesn’t work since the variable isn’t evaluated but taken literally

{% set my_scene = ... %}
{{ states.scene.my_scene.state is defined  }}

Attempt 2 - nesting templates doesn’t seem to be supported

{% set my_scene = ... %}
{{ states.scene.{{my_scene}}.state is defined  }}

Is there even syntax that can help me here?

Thank you!

EDIT: as an alternative, is it reliable to instead do this

{{ is_state('scene.' + my_scene, "unknown") }}

or it may be unknown for other reasons than the scene not existing (e.g. while HA is starting up and everything is getting loaded)? I.e. is there situations where .state is defined will return true but the above will still return ‘unknown’.
Thanks very much!

{% set my_scene = ... %}
{{ states.scene[my_scene].state is defined  }}
2 Likes

THANK YOU Taras!

1 Like

OR …

{{ has_value('scene.{}'.format(my_scene))}}