Fixed delay between hass.services.call()'s in a python script

Is there a way to insert a delay in a python script? Specifically, I need a fixed delay (a variable number of seconds) between hass.services.call()'s, so I can turn on switches in a timed sequence. I assume I need to set blocking=True, but that’s as far as I’ve gotten. I tried importing ‘time’, but that doesn’t work. I tried looking for a service like the ‘delay’ function in a non-python script or automation, but couldn’t find anything.

Delay’s are typically a bad thing to insert. They block the thread they are on, and that kills performance.

If you are comfortable with python you might want to check out AppDaemon, it could be done pretty easily there. It’s a native python interface to HA with a bunch of helper functions to make coding your automations pretty simple.

Yes, I understand that conceptually, but I was under the impression that the python_scripting feature in HA was running those scripts in a sandbox on a separate thread, so that anything I did within that thread wouldn’t affect the HA itself. Is that a misunderstanding?

I read that as well. But I don’t know if it’s a separate sandbox for each script, or one sandbox that all python scripts run in.

Any ideas at all? It’s possible to add a delay to an automation using “delay”, but I don’t see that “delay” is exposed as a service (else maybe you could call the “delay” service with blocking=True).

The script is run in the the event loop and must not block, so delay or sleep is not possible (and never will be). You will either have to use delay in automatons, use appdaemon or some other solution utilizing the external API.

I just want to add to this subject that time.sleep() is now possible to use. I found this while searching and I’m glad I continued searching, since it’s now implemented.

1 Like

Awesome! Thanks for posting this . . . I’ve been trying to track down a way to simply throttle my automation, and now it works brilliantly. I’m glad I kept searching too to see this response. And, I also finally found the details from @balloob note on these updates/fixes!

Unfortunately, the documentation for Python Scripts could use alot of ‘love’ and expansion to be truly helpful…

My use case is a Python Script with a while loop that tracks the state of a Lutron Caseta Pico remote and calls a RESTCommand to update the volume on the Denon AVR-X4300 reciver… it was working well with no delay, but was tough to make a single .5db change, it would jump 1.5-3dm with each press. Now it works brilliantly with a simple time.sleep(.065) throttle call!

Amazing Use of Python Script, still can’t believe how well this works with the Lutron Caseta SmartBridge Pro custom component!

    loop_enabled = True
    sleep_time = .065

    while loop_enabled:
    	# Obtain status of the Pico Remote
    	pico_status = hass.states.get("sensor.living_room_audio_pico")
    	if pico_status.state == "8":
    		#Call the volume Up REST Command
    		hass.services.call("rest_command", "denonavr_volume_up", None, True)
    		time.sleep(sleep_time)
    	elif pico_status.state == "16":
    		#Call the volume Down REST Command
    		hass.services.call("rest_command", "denonavr_volume_down", None, True)
    		time.sleep(sleep_time)
    	else:
    		loop_enabled = False

And for anyone curious (or searching for a stable way to control the Denon AVR volume on an X series (e.g. AVR-X4300H), here are my REST Commands:

    #REST Commands
    rest_command:
      #Stable/Reliable REST commands to control AVR-X4300H where the denon/denonavr components do not work correctly/reliably
      #NOTE: %0D is Url Encoded <CR> character required by the Denon API
      #NOTE: Denon API: http://openrb.com/wp-content/uploads/2012/02/AVR3312CI_AVR3312_PROTOCOL_V7.6.0.pdf
      denonavr_power_on:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?PWON%0D'
      denonavr_power_off:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?PWSTANDBY%0D'
      denonavr_volume_up:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MVUP%0D'
      denonavr_volume_down:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MVDOWN%0D'
      denonavr_volume_low:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MV40%0D'
      denonavr_volume_medium:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MV55%0D'
      denonavr_volume_high:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MV72%0D'
      #This one supports Setting SPECIFIC Volume level from an Automation via:
      # data:
      #   volume: 50
      # OR via Python script as follows:
      # hass.services.call("rest_command", "denonavr_volume_set", {"volume": "40"})
      denonavr_volume_set:
        url: 'http://192.168.1.12:8080/goform/formiPhoneAppDirect.xml?MV{{ volume | int}}%0D'

UPDATED 02/06/2018:
Here’s another fun little snippet I added recently using the REST Command and dynamic parameters. The dynamic param is an EXCELLENT feature, but I was unaware that it was supported because the documentation is weak and does not elaborate on this very well at all . . . saying only “Service call support variables for template stuff.” This could really use some explanation and at least one sample (such as this one)!

When my wife wants to hit the “Yoga Time” button on the remote, using the very innovative Emulated Roku custom component here… my Harmony Remote can trigger a Python Script which lets me launch the Yoga Scene, set the volume to her favorite level, and launch the Yoga video on Kodi all with the press of a button!

Using the REST Command above for setting the Volume directly via parameter the following script calls it and passes 40 as her favorite level!

#Get the current Harmony remote Activity
current_activity = hass.states.get("sensor.htpc_remote_current_activity").state

if theater_mode_value == "yoga_time":
	hass.services.call("scene", "turn_on", {"entity_id": "scene.yoga_time_scene"})
	#Set the Volume to 40 for Yoga Time!
	hass.services.call("rest_command", "denonavr_volume_set", {"volume": "40"})
	
	if current_activity != "Watch Kodi":
		#IF NOT already on correct activity, then we turn on Kodi!
		hass.services.call("remote", "turn_on", {
			"entity_id": "remote.htpc_remote",
			"activity": "Watch Kodi"
		})
	
2 Likes