Halloween Automations?

skeleton projector? impressive

Almost 4 years later but it is soon that time of the year again… :skull:

I wrote a small script for the python_integration which toggles any set of lights on and off in random groups, with random colors and in random intervals. The upside of writing it in a script is that I can use millisecond wait time, the downside is that the sleep function slows down homeassistant so I am not running it all night long. My idea is to let my doorbell motion toggle an input_boolean on, and when noone has been there for 5 minutes turn it off. Then another automation to run it every once and then during the night.

Python script (named disco.py):

def sleep(millis):
    end = datetime.datetime.now() + datetime.timedelta(milliseconds=millis)
    while datetime.datetime.now() < end:
        pass

def toggle(lights, brightness, color):
    hass.services.call('light', 'toggle', {'entity_id': lights, 'brightness_pct': brightness, 'rgb_color': color})
    logger.debug("Toggle lights: %s, %s, %s", lights, color, brightness)

switch = data.get("switch")
lights = data.get("lights", [])
colors = data.get("rgb_colors", [255, 255, 255])
brightness_min = max(data.get("brightness_min", 1), 1)
brightness_max = min(data.get("brightness_max", 100), 100)
sleep_min_ms = max(data.get("sleep_min_ms", 1500), 1)
sleep_max_ms = max(data.get("sleep_max_ms", 5000), 1)

input_is_ok = True

if hass.states.get(switch) is None:
    input_is_ok = False
    logger.warn("%s is not a valid homeassistant entity!", switch)

if len(lights) == 0:
    input_is_ok = False
    logger.warn("No lights defined, disco is cancelled!")

if input_is_ok:
    while hass.states.get(switch).state == 'on':
        lights_to_toggle = random.sample(lights, random.randint(1, len(lights)))
        color = random.sample(colors, 1)[0]
        brightness_value = random.randint(brightness_min, brightness_max)
        sleep_value = random.randint(sleep_min_ms, sleep_max_ms)
        
        toggle(lights_to_toggle, brightness_value, color)
        logger.debug("Now sleeping for %s", sleep_value)
        
        sleep(sleep_value)

logger.info("Exiting disco")

I use the input_boolean as source, and as long as it is set to on the script continues. Automation to start the script with halloween themed parameters:

- alias: Turn on halloween disco
  initial_state: 'on'
  trigger:
    platform: state
    entity_id: input_boolean.halloween_lights
    to: 'on'
  action:
    - service: python_script.disco
      data:
        switch: input_boolean.halloween_lights
        lights:
          - light.outside1
          - light.outside2
          - light.outside3
          - light.outside4
          - light.outside5
        rgb_colors:
          - [255, 193, 0]
          - [255, 140, 0]
          - [255, 116, 0]
          - [255, 69, 0]
          - [255, 0, 0]
        brightness_min: 15
        brightness_max: 90
        sleep_min_ms: 500
        sleep_max_ms: 3500
1 Like

To add to this 1 year later, it is the time of the year after all…:ghost:
I altered the script of @Miicroo even more to provide more compatibilty and ‘features’.

Changes include:

  • Compatibility with ‘brightness-only’ bulbs (e.g. Hue Filament)
    This also opens up the possibility to set only color or brightness (or both, ofcourse).
  • Brightness is entered as a list instead of min/max to have more control over the chosen levels (e.g. for flashing lights). This however does remove the randomness between min/max levels.
  • Some code optimalization

light_random_effect.py:

#Script input data
switch = data.get("switch")
lights = data.get("lights", [])
colors = data.get("rgb_colors", [])
brightness_pct = data.get("brightness_pct", [])
sleep_min_ms = max(data.get("sleep_min_ms", 1500), 1)
sleep_max_ms = max(data.get("sleep_max_ms", 5000), 1)

#Provided switch is valid
if hass.states.get(switch) is None:
    input_error = True
    logger.warn("Light random effect: %s is not a valid entity!", switch)
#Any light entity is specified
elif len(lights) == 0:
    input_error = True
    logger.warn("Light random effect: No lights defined")
#Any color and/or brightness is specified
elif len(colors) == 0 and len(brightness_pct) == 0:
    input_error = True
    logger.warn("Light random effect: No color or brightness defined")
#No errors
else:
    input_error = False

#Run script
if not input_error:
    while hass.states.get(switch).state == 'on':
        #Take random light from list
        random_entity_id = random.sample(lights, random.randint(1, len(lights)))
        #Take random color from list
        if len(colors) > 0:
            random_rgb_color = random.choice(colors)
        else:
            random_rgb_color = None
        #Take random brightness
        if len(brightness_pct) > 0:
            random_brightness_pct = random.choice(brightness_pct)  
        else:
            random_brightness_pct = None

        #Turn off
        if random_brightness_pct == 0:
            hass.services.call('light', 'turn_off', {'entity_id': random_entity_id})
        #Turn on: Set brightness
        elif random_brightness_pct != None and random_rgb_color == None:
            hass.services.call('light', 'turn_on', {'entity_id': random_entity_id, 'brightness_pct': random_brightness_pct})
        #Turn on: Set brightness and color
        elif random_brightness_pct != None and random_rgb_color != None:
            hass.services.call('light', 'turn_on', {'entity_id': random_entity_id, 'brightness_pct': random_brightness_pct, 'rgb_color': random_rgb_color})

        #Take random sleep value
        random_sleep_value = random.randint(sleep_min_ms, sleep_max_ms)
        #Sleep
        end = datetime.datetime.now() + datetime.timedelta(milliseconds=random_sleep_value)
        while datetime.datetime.now() < end:
            pass

Some examples on how to use this.
Please take a look at Python Scripts how to enable python scripts.

Flashing white, simulating lightning

service: python_script.light_random_effect
data:
  switch: input_boolean.your_switch_goes_here
  lights:
    - light.your_light_goes_here
  rgb_colors:
    - [255, 255, 255]
  brightness_pct:
    - 1
    - 1
    - 1
    - 100
  sleep_min_ms: 150
  sleep_max_ms: 300

Flickering light, like the light is broken.

service: python_script.light_random_effect
data:
  switch: input_boolean.your_switch_goes_here
  lights:
    - light.your_light_goes_here
  brightness_pct:
    - 40
    - 40
    - 40
    - 10
  sleep_min_ms: 150
  sleep_max_ms: 300

Hope this helps out anyone creating some more cool effects.
Do note, by setting the sleep time very short, it is possible to ‘overload’ the ZigBee network.
This is spoken from experience, whereas my lights kept doing effects long after the switch was disabled.

4 Likes

Sweet!

This year I just settled for treating the trick’n’treaters with the lamp turning red when they hit the doorbell followed by a bloodcurdling scream from a battery of Sonos speakers :slight_smile:

1 Like

Don’t even get me started on a project like this or no other work will get done! I don’t do much for Halloween, honestly, but the little I do could probably be geeked out pretty well, but then another 8 hours of time down the drain :joy:

absolutely fantastic stuff. thank you for the solution and examples. if you wanted to allow the old functionality on how brightness used to work you could also detect if the list length of brightness was 1 and the single brightness value was -1 or something… and then just choose a brightness between 0 and 100.

*first edit: so, one hint… i momentarily struggled with how to use the script concurrently for multiple effects in the same automation. i created an input boolean to haunt my office. inside an automation i have the input boolean as a trigger and initially i setup three actions with three services calls to the same python script. if you do that the first script doesn’t give up control and it only sits there continuing to execute only on the first action. if you instead setup a “run in parallel” action and then put the three service calls inside that it will work.

makes sense but i thought i would call it out for rookies like me.

*second edit: this was a wonderful way to bog down my home assistant instance to the point of absolute instability :slight_smile:

*third edit: if you are feeling totally destructive here is a switch version. i take no responsibility for issues you may cause if you use this. lights are fairly safe. switches can be a nuisance if they are solid state relays (which can wear out) or have dangerous things attached to them (like sensitive electronics or coffee makers or hair dryers or something). i have a lot of zen71 zooz z-wave switches which only show up as switches. i think i can change them to lights with helpers but i’m not going to do that. i did this instead. use with caution.

switch_random_effect.py

#Script input data
switch = data.get("switch")
lights = data.get("lights", [])
sleep_min_ms = max(data.get("sleep_min_ms", 1500), 1)
sleep_max_ms = max(data.get("sleep_max_ms", 5000), 1)

#Provided switch is valid
if hass.states.get(switch) is None:
    input_error = True
    logger.warn("switch_random_effect.py: %s is not a valid entity!", switch)
#Any light entity is specified
elif len(lights) == 0:
    input_error = True
    logger.warn("switch_random_effect.py: No lights defined")
#No errors
else:
    input_error = False

#Run script
if not input_error:
    while hass.states.get(switch).state == 'on':
        #Take random light from list
        random_entity_id = random.sample(lights, random.randint(1, len(lights)))

        #Toggle
        hass.services.call('switch', 'toggle', {'entity_id': random_entity_id})

        #Take random sleep value
        random_sleep_value = random.randint(sleep_min_ms, sleep_max_ms)
        #Sleep
        end = datetime.datetime.now() + datetime.timedelta(milliseconds=random_sleep_value)
        while datetime.datetime.now() < end:
            pass

*fourth edit: lol… okay, i’m done after this. a usage…

turn on and off randomly between 3 and 10 seconds

service: python_script.switch_random_effect
data:
  switch: input_boolean.your_trigger_switch_goes_here
  lights:
    - switch.your_light_that_is_a_switch_here
  sleep_min_ms: 3000
  sleep_max_ms: 10000
enabled: true
1 Like