Python_script to save and restore switches and lights

I needed a way to save the current state of some switches and lights so I could change them temporarily, and then restore them back to the way they were. Somewhat surprisingly, HA doesn’t seem to have a native feature for this. (If I’m wrong, by all means, enlighten me! :slight_smile:)

UPDATE: Starting with release 0.103.0, HA now does have a native feature for this – namely dynamic scene creation using the snapshot_entities option. See the docs here. It doesn’t provide all the functionality of the script described here, but it should suffice in most cases.

So I searched the forum and found that the common technique was to create various input_boolean, etc. entities and then write various automations and scripts to get the job done. That seemed a bit cumbersome at best.

So, since the State Machine is basically a big, global variable, and can pretty much save whatever, I wrote a python_script that can save, and later restore, the states of switches and lights.

You can find information about how to install and use the script here.

20 Likes

Fantastic, I was about to hack my way through an input boolean/mqtt scheme. Looking forward to trying this.

Could I create multiples of this script by changing the file name and associated automation calls? It would be nice to separate some of my groups of lights.

I hope it works for you. I’ve been using it for a little while and a few others have, too. But if you have any feedback, I’m all ears.

You shouldn’t have to make copies of the script. Just use different store_name's. E.g.,

script1:
  sequence:
    - service: python_script.light_store
      data:
        store_name: light_store_1
        entity_id: ...

script2:
  sequence:
    - service: python_script.light_store
      data:
        store_name: light_store_2
        entity_id: ...

Perfect. I’ll try to give it a call tonight. I’ll be sure to give feedback either way.

1 Like

Added support for groups (i.e., from the group component, not from the light component.)

1 Like

Moved code to github.

Thanks for the script.

I tested this out… was scratching my head as to why HA kept complaining that it couldn’t find the script, then I realised I had to add python_script: to my configuration.yaml :relieved:

I’ve setup the following:

  1. Backup specific light.
  2. Change color and brightness (green)
  3. Change color and brightness (red)
  4. Restore light from step 1.

This works fine when the light is already on.

If the light is off and the script is ran, the light turns on, green then red then powers off. But the next time the light is turned it still seems to be red.

Have I configure something wrong?

The problem probably is due to the fact the light entity has no color (our brightness) attribute (in HA) when it is off, so there’s no way for the script to save any color or brightness values. Check out the light entity on the states page when it’s off and you’ll see. So the light is probably just turning on the next time to whatever color it was the last time it was on. You may want to add a step to change the color and/or brightness before the last step of restoring.

Awesome, thanks for confirming. I wanted to make sure it wasn’t a misconfiguration on my end. I did check the states and thought this was the case.

I was going to add a check if the light is off, to turn it on first, then store the on state, change color, restore then switch it off.

Thanks a lot and cheers for the script.

1 Like

I did further testing on this and found the following:
I started with a LIFX preset (2750K Incandescent) using the LIFX app and this was the states attributes in hass.

brightness: 77
color_temp: 363
hs_color: 0,0
rgb_color: 255,255,255
xy_color: 0.323,0.329

SAVE: I then used the script to save the state of the LIFX and then alter the color. At this stage I checked the states/attributes.
entity: light_store_light_living_room.light_living_room
state: on
brightness: 77
hs_color: 0,0

RESTORE: I then restored the state and checked the states again and got the following:
brightness: 77
color_temp: 285
hs_color: 0,0
rgb_color: 255,255,255
xy_color: 0.323,0.329

For some reason when it’s restored the color_temp is different from the save and restore state.

This also happens when not using the LIFX app and just hass. I’ll set the color_temp in hass, save, restore and the color_temp value changes.

I browsed the light component and lifx platform code a bit and I’ll admit I don’t fully understand how they use all these different representations of color.

It looks like when using the light.turn_on service that you can only use one of profile, color_name, hs_color, xy_color, rgb_color, color_temp or kelvin. Then the code converts as necessary. E.g., in the light component code, profile, color_name, xy_color and rgb_color all seem to ultimately get converted to hs_color. Also, kelvin gets converted to color_temp. So ultimately, only hs_color or color_temp is used (again, after possibly being converted from another input value), but not both. Then in the lifx code it further converts either hs_color or color_temp (depending on which was provided) to hue/saturation/kelvin, and that is apparently what it uses to set the color of the bulb.

Then when setting the entity’s attributes, the lifx platform sets hs_color and color_temp (based on the color it set), and the light component adds xy_color and rgb_color (converted from hs_color.)

Now I’m no color expert, but from the little I researched, I don’t see how a color_temp of 363 is equivalent to an hs_color of 0,0.

In any case, I think the bottom line is you’re setting the color via color_temp (or possibly via kelvin that gets converted to color_temp), and the lifx platform is representing that with an hs_color that is not equivalent. Then my script saves and restores (the invalid) hs_color, resulting in an incorrect color_temp. Of course, I could still be misreading things. If someone knows more about this, maybe they can help.

But, at least for now, assuming I’m correct that you’re using color_temp or kelvin when turning the light on, then I would suggest making a minor change to my script. I.e., change the following:

# Select light attributes to save/restore.
ATTR_BRIGHTNESS = "brightness"
ATTR_HS_COLOR = "hs_color"
LIGHT_ATTRS = [ATTR_BRIGHTNESS, ATTR_HS_COLOR]

to:

# Select light attributes to save/restore.
ATTR_BRIGHTNESS = "brightness"
ATTR_COLOR_TEMP = "color_temp"
LIGHT_ATTRS = [ATTR_BRIGHTNESS, ATTR_COLOR_TEMP]

If that works, and someone can fill in a bit more about the relationship between hs_color and color_temp, then there might be a more elegant way for my script to handle this situation.

Thanks for looking into this. I can confirm that in my script/automation I do in fact use color_name to set green and red and yellow. I’ll try and use hass to set the color using the hs_color, but from what I found hs_color = 0,0 only represents white and does not contain the color_temp or kelvin.

I did have a quick look at your script and attempted to guess the code and updated this:
ATTR_BRIGHTNESS = "brightness"
ATTR_HS_COLOR = "hs_color"
ATTR_HS_COLOR_TEMP = "hs_color"
LIGHT_ATTRS = [ATTR_BRIGHTNESS, ATTR_HS_COLOR, ATTR_HS_COLOR_TEMP]

It saves the values, but I get an error when it attempts to restore.

As I mentioned, the light component will convert color_name to hs_color itself, so you shouldn’t need to try using hs_color.

I agree that hs_color == (0,0) would represent white (or some shade of grey depending on brightness.) However, I disagree that hs_color does not “contain” (or can’t be converted to) color temperature. In fact, homeassistant.util.color contains several color conversion routines, and using them, a color_temp of 363 (the color_temp you got when you first turned on your bulb) equates to 2754 kelvin (which is about what your preset of 2750K was), which equates to an hs_color of (28.281, 64.025). Here is how I achieved those numbers:

>>> import homeassistant.util.color as uc
>>> uc.color_temperature_mired_to_kelvin(363)
2754
>>> uc.color_temperature_to_hs(2754)
(28.281, 64.025)

But, from what you showed above, your LIFX bulb represented its hs_color instead as (0,0). This is the problem: it’s setting its color_temp attribute correctly, but not its hs_color attribute.

This is why I said to change my script to save & restore color_temp instead of hs_color. If you did exactly that, I’m pretty sure it would work for you, at least with this bulb.

LIFX describes colors with [hue, saturation, brightness, kelvin].

The saturation is the balance between hue and kelvin. To get a white light, we set saturation to 0 (full white) and then the hue does not matter.

Setting a non-zero saturation (i.e. a colored light) always returns kelvin to 3500 so the desaturation happens with a neutral white.

This should explain what you see but let me know if it is still not clear :slight_smile:

I’m not the one with the LIFX bulb, so I’m not seeing anything other than what @q00dee is reporting when trying to use a script I wrote.

My script saves a light entity’s hs_color attribute (if the light is currently on, and its entity currently has that attribute), and when restoring, if the light was on and had the hs_color attribute, uses the saved hs_color value.

However, the hs_color value his LIFX entity is reporting (0,0) doesn’t seem to be valid for the color_temp (363), so when restoring the color gets set incorrectly. It seems to me that if the light’s color_temp is 363, then the light entity’s hs_color attribute should be reported as (28.281, 64.025), not (0,0). Everything I’ve read while researching this situation seems to indicate (0,0) is wrong for a color_temp of 363 (mireds, or 2754K.) But again, I’m not an expert.

Regardless, it would seem if the script is changed to save/restore color_temp instead of hs_color, it might work in this case.

Thanks @pnbruckner ! I have altered the script from hs_color to color_temp and that seems to work. :+1:

I have also observed in my testing that initially there is definitely a hs_color value that corresponds to the correct value, but somehow is ends up being 0,0 and eventually the hs_color reverts to the correct value.

Glad to hear it. I’ll think about a way to make the script more generic, like seeing if hs_color, color_temp or both are present. If one of the other, then it’s pretty clear to save (& restore) that attribute. But if both are present, and worse, like in this case they disagree, then I’m not sure what would be best to do. Maybe chose color_temp because we know at least LIFX seems to have a bug in its reporting of hs_color???

Yeah, that definitely sounds like a bug. You might want to consider looking into that, or at least somehow informing the author. Maybe it’s just a transient issue. I.e., when you change the light, hs_color is only temporarily wrong, so if you delay a bit before saving???

Just ignore hs_color (hue/saturation) and use color_temp if the current saturation is zero.

I guess you can argue that light platforms should return just one or the other so I made a PR for LIFX to do that: https://github.com/home-assistant/home-assistant/pull/15234

However, this issue will affect other light types as well.

Probably a dumb question - I was looking at this to cover off when I’m working on HA and my wife is home; when I restart HA the lights stay on until it restarts and then they all turn off (usually, I seem to pick the most inopportune time to do this) – Could this be used to save the light states when they’re turned on and then on HA start trigger a restore? The idea being that when I restart HA, the lights may blink out momentarily but are restored to last known state?

PS… I just posted this as I recently just had an inopportune moment while my wife was cooking :stuck_out_tongue:

I don’t think so. I don’t think HA restores states in the state machine, which is what this uses. I think HA only restores certain entities (like input_xxx’s, automations, scripts, and maybe a few more) to their previous state during startup (which, of course, causes state changes from none to something that repopulates those states into the state machine.)

What type of lights do you have? I use Z-Wave exclusively interacting directly with HA via a Z-Wave controller stick. They don’t change due to a HA restart. (HA just updates their current states into the state machine.) Maybe it’s something about how you have your light entities configured that needs adjusting.