Can't sleep! Try this

That worked for me. Thanks!

Great - hope that it proves interesting to you. Amazingly it needs to be fairly bright so you can see the on/off sequence with your eyes closed. Blue is a good choice of colour. The sequence between off-to-on and on-to-off in this setup is equal. The on-to-off step is supposed to be longer. The sequence is suppose to run for about 15 minutes what I have works for me.

Did a Yaml version of this happen? Iā€™m interested if so. Donā€™t have NR so not keen to pursue that route.

@Isablend - no a yaml version does not exist (yet). I renamed the flow.json file to flow.yaml so that I could upload it. To import this you will need node-red.

I couldnā€™t resist having a go, but ultimately failed in writing this in yaml, just couldnā€™t get the timing right, so i gave it a go using appdaemon, and it turns out to be a relatively easy thing to do. Having spent a bit of time learning about appdaemon, I think I will use it for more complex automations in future.

So I have a light defined and in input boolean to allow switching on and off (also allows for an Alexa initiation). Iā€™ve defined 5 variables in the accompanying .yaml file which define the number of minutes for the thing to run, the starting breaths per minute and the ending breaths per minute, along with the maximum and minimum light settings (expressed as a percentage).

The appdaemon code is then as follows;

import appdaemon.plugins.hass.hassapi as hass
import time

# App to turn a light into a sleep inducer 
# Turns the light on and off to mirror breathing pattern
# slowly reducing the rate of breaths over a stated period of time

class Sleep_Inducer(hass.Hass):

    # Initialise all of the necessary variables for the app 
    def initialize(self):
        self.si_min = int(self.args["sleep_inducer_minutes"])
        self.st_bpm = int(self.args["starting_breaths_per_minute"])
        self.end_bpm = int(self.args["ending_breaths_per_minute"])
        self.max_bri = int((255/100)*int( self.args["max_brightness"]))
        self.min_bri = int((255/100)*int( self.args["min_brightness"]))

        self.listen_state(self.SleepInducerOn, "input_boolean.sleep_inducer", new="on")
 
    def SleepInducerOn(self, entity, attribute, old, new, kwargs):
        if new == 'on' :

           # execute for a set number of minutes 
           for minute_count in range(self.si_min):

               # calculate the breath time for this minute's iteration
               breath_number = int( ( ( -0.125 * ( self.st_bpm - self.end_bpm ) ) * minute_count ) + self.st_bpm )
               breath_time = float( 60 / ( ( ( -0.125 * ( self.st_bpm - self.end_bpm ) ) * minute_count ) + self.st_bpm ) )

               # set number of times in the current minute to breath
               for breath_count in range(int(breath_number)):

                   # breath in - 3/5 of breath_time
                   breath_in=breath_time*(3/5)
                   self.turn_on("light.sleep_inducer",
                                color_name = "blue",
                                transition = int(breath_in), 
                                brightness = self.max_bri)
                   # pause to let the light catch-up
                   time.sleep(breath_in)

                   breath_out=breath_time*(2/5) 
                   # breath out - 2/5 of breath_time
                   self.turn_on("light.sleep_inducer",
                                transition = int(breath_out), 
                                brightness = self.min_bri)
                   # pause to let the light catch-up
                   time.sleep(breath_out)

                   # check that it has not been cancelled
                   continue_si=self.get_state('input_boolean.sleep_inducer')
                   
                   # drop out of breath_count loop
                   if continue_si=='off' :
                      break

               # drop out of minute_count loop
               if continue_si=='off' :
                  break

           # turn off the sleep_inducer switch
           self.turn_off("input_boolean.sleep_inducer")
           # turn the light off
           self.turn_off("light.sleep_inducer")

Iā€™m sure itā€™s not perfect, but it works and has opened up a whole new area for me to investigate.

3 Likes

Hi seems to be working fine but it doesnā€™t turn off with the button manually , it turns of by itself after certain time only ? I used the flow that you sent @GeoffAtHome

Tried rewriting in as a package in yaml and using scenes to set what required. Appears to work and simpler to edit.

#
# Based on the Dodow video
# Duration: 8 minutes (480 seconds)
# Initial breathing: 11 breaths a minute (once every 5.45 seconds (60/11) )
# Final breathing: 5 breaths a minute (once every 12 seconds (60/5) )
#
# This equates to slowing down from breathing once every 5.45 seconds
# to once every 12 seconds over eight minutes
# which is about 55 cycles
# Each cycle we need to add a delay of about 0.08727 seconds
#
# The scenes need to be create for the light that is going to be used.
# The scenes are:
#     scene.spl_breathing_in
#     scene.spl_breathing_out
#     scene.spl_breathing_end
#
# scene.spl_breathing_in - turns the light on. Must be bright enough to see with you eyes closed but not too bright
# scene.spl_breathing_out - dims the light down. Could be total off if needed
# scene.spl_breathing_end - turns the light off at the end running the script

# Everything needs to be divided by two as we are breathing in and out
#
input_number:
  initial_breathing:
    initial: 2.72
    min: 0.0
    max: 60.0

  final_breathing:
    initial: 6.00
    min: 0.0
    max: 60.0

  delta:
    initial: 0.43535
    min: 0.0
    max: 1.0

  current_breathing:
    initial: 5.45
    min: 0.0
    max: 60.0

script:
  sleepy_lights_start:
    alias: Start sleepy
    sequence:
      - service: input_number.set_value
        entity_id: input_number.current_breathing
        data_template:
          value: '{{ states("input_number.initial_breathing") | float }}'
      - repeat:
          while:
            - condition: template
              value_template: '{{ states("input_number.current_breathing") | float < states("input_number.final_breathing")| float }}'
          sequence:
            - service: input_number.set_value
              entity_id: input_number.current_breathing
              data_template:
                value: '{{ states("input_number.current_breathing") | float + states("input_number.delta") | float}}'
            - service: scene.turn_on
              target:
                entity_id: scene.spl_breathing_in
              data_template:
                transition: '{{ states("input_number.current_breathing") | float }}'
            - delay: '{{ states("input_number.current_breathing") | float }}'
            - service: scene.turn_on
              target:
                entity_id: scene.spl_breathing_out
              data_template:
                transition: '{{ states("input_number.current_breathing") | float }}'
            - delay: '{{ states("input_number.current_breathing") | float }}'
      - service: scene.turn_on
        target:
          entity_id: scene.spl_breathing_end