Introducing delay into device handler?

I’m having a bear of a time getting a (what i thought) was a 1-2 second delay on a device handler

raspberry pi zero w
2 port relay, of which one port is connected to garage door trigger
WEBIOPi for the REST api calls

device handler calls /gpio/port/on then callback issues /gpio/port/off
it’s that on/off that’s killing me. it fires off almost instantly and the garage door needs something like 1-2 seconds of “on” to register the click. sometimes it fires but more often than not i’m repeatedly pressing my trigger to make it work.

my code is horrible, i’m not even going to try to say it’s good. what am i missing for introducing this delay?

preferences {

    section("Internal Access"){
		input "internal_ip", "text", title: "Internal IP", required: false
		input "internal_port", "text", title: "Internal Port (probably 8000)", required: false
		input "internal_on_path", "text", title: "Internal Path (/GPIO/number/)", required: false

metadata {
	definition (name: "URI Switch", namespace: "athlonduke", author: "me") {
		capability "Switch"

	// simulator metadata
	simulator {

	// UI tile definitions
	tiles {
        standardTile("toggleButton", "device.button", width: 2, height: 2, canChangeIcon: true) {
			state "default", label: 'Toggle', action: "switch.on", icon: "st.Transportation.transportation12", backgroundColor: "#bbff21"
		main "toggleButton"
			details (["toggleButton"])

def parse(String description) {
	//log.debug "i'm over there"

def parse(physicalgraph.device.HubResponse hubResponse){
	//log.debug "in parse: ${hubResponse.body}"



def on() {
	log.debug "Sending pulse"

def reallyTurnOn(){
	def port=port()
        def result = new physicalgraph.device.HubAction(
            method: "POST",
            path: "${internal_on_path}function/out",
            headers: [
                HOST: "${internal_ip}:${port}"
            [callback: parse]

            "delay 1000"
        //sendEvent(name: "switch", value: "on")
        log.debug result


def reallyTurnOff(){
	def port=port()
	def result2 = new physicalgraph.device.HubAction(
		method: "POST",
		path: "${internal_on_path}function/in",
		headers: [
			HOST: "${internal_ip}:${port}"
            "delay 1000"
		//sendEvent(name: "switch", value: "off")
        log.debug result2   

def port() {
	def port=80
	if (internal_port){
		port = "${internal_port}"
    return port

If you really only need to wait 1 or 2 seconds (1000 to 2000 milliseconds), then, frankly, using a busy-wait loop may be the most practical way to just get this done.

This is inefficient / impolite code, but since it won’t run very frequently or loop for very long, no big deal.

Add this method and call it when needed. Remove the log.debug lines after testing.

def pause(millis) {
   def passed = 0
   def now = new Date().time
   log.debug "pausing... at Now: $now"
   /* This loop is an impolite busywait. We need to be given a true sleep() method, please. */
   while ( passed < millis ) {
       passed = new Date().time - now
   log.debug "... DONE pausing."


Should be:


You could try using 3-4 if 1-2 seconds is a little too fast.


Supposedly runIn with less than 60 seconds is unreliable (but perhaps it has been improved).

The theory is that by the time the task is added to the scheduler, more than several seconds will have gone by already…

The original code snippet had a bug in it. It could be the reason why it’s running immediately (calling the method instead of scheduling it).

I’ve seen runIn run very reliably 95%+ of the time. What ST means by that is that the maximum time not guaranteed. So 2 second delay could be a 4 second (or more) delay which I’ve seen occasionally.

RBoy, what did i screw up? i’d like to fix it
edit: derp. i see it now. i’ll clean it up, thanks!

tgauchat, thanks, that did the trick! it’s working reliably now