Sequence of RunIn()'s stop running after several minutes


(Vishal Kumar) #1

Hello -
I have written a SmartApp that sends an HTTP GET every 3 seconds, parses the response, and from that determines whether to turn on or off a SmartPower outlet. I do this by using RunIn() statements. Code is below. For some reason, the app gets going okay, but then stops executing after an inconsistent number of minutes. No errors - just stops sending the HTTP GETs. Is there something fundamentally incorrect in the way I’m using the RunIn()'s?

Thanks so much in advance for any advise or guidance. Cheers!

definition(
    name: "Dweet SmartPower Demo",
    namespace: "buglabs",
    author: "Vishal Kumar",
    description: "Allows communication to/from the SmartPower outlet via Dweet.io.",
    category: "My Apps",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png") {
}


preferences {
	section("Title") {
		// TODO: put inputs here
	}
    section("Dweet as...") {
      input "thingname", "text", title : "Enter a name to dweet from..."
  	}
    section("Allow External Service to Control These Things...") {
    	input "switch0", "capability.switch", title: "Which Switch?", multiple: false, required: true
    }
}


def installed() {
	log.debug "Installed with settings: ${settings}"
	initialize()
}

def updated() {
	log.debug "Updated with settings: ${settings}"
	//state = switch0.currentState("switch")
	unsubscribe()
	initialize()
}

def initialize() {
	//$currstate = switch0.currentState("switch").getValue()
	//subscribe(switch0,"switch",saveSwitchState)
    runIn(2,"sendDweet")
}

// Send the current status of lightswitch 
def sendDweet() {
  def currstate = switch0.currentState("switch").getValue()
  httpGet([
    uri   : "http://dweet.io/",
    path  : "dweet/for/" + thingname,
    query : [ 
      "light" : currstate
      //"contact" : item.currentValue('contact'), 
      //"degrees" : item.currentValue('temperature'), 
      //"unit" : "F" 
    ],
    success: { response ->
      log.debug "Dweet sent successfully!"
    }
  ])
  runIn(3,"getDweet")
}

// Check for external requests to turn light on/off
def getDweet() {
  httpGet([
    uri   : "http://dweet.io/",
    path  : "get/latest/dweet/for/" + thingname + "-send",
    query: [format: 'json', body: jsonRequestBody],
    success: { response ->
      log.debug "Request was successful!"
      if (response.data.containsKey("with")){
        if (response.data.with.content[0].containsKey("light")){
          def content = response.data.with.content.light       
          //log.debug "$content"
     	  if (content[0] == 'on') {
			if(switch0.currentState("switch").getValue() == 'off') {
            //log.debug "$switch0.currentState('switch')"
	            switch0.on()
            }
          } 
          else if (content[0] == 'off') {
          	if(switch0.currentState("switch").getValue() == 'on'){
           		switch0.off()
           	}
          }
        }
      }      
    }
  ])
  runIn(3,"sendDweet")
}

def saveSwitchState(evt) {
  currstate = switch0.currentState("switch").getValue()
}

(swanny) #2

I had the same issue. I think there is some kind of server side throttling that goes on with the RunIn calls. I think it was mentioned during the online SmartApp workshop that it is recommended to use 1 minute or longer with RunIn (which isn’t very convenient in many cases I know). I seemed to have more luck moving out to 8 seconds than I did with a smaller number.

Someone else may have more exact details though, and I’d be happy to learn more about it rather than speculate. :smile:


(Yogesh Mhatre) #3

On a related note,

Is there a way I can pass argument while calling the function in runIn()
Example - runIn(10, logout(token))

Basically I want to delay execution of logout() with passing an argument by 10 seconds. At the moment, pause(10000) works, but I would prefer runIn()


(Tim Slagle) #4

You can only have 4 scheduled events at one time. If you hit that limit the app will stock dead cold.


(Chrisb) #5

I think it would be better to attack this by trying to schedule a cron job to run every 3 minutes rather than using runIn.


(Convinced ST will never be unbroken…) #6

I noticed the other day when writing an app using runIn, that it would not schedule on any value less than 60. Don’t know if that was just a fluke with SmartThings and the simulator, but the behavior was very consistent at the time.


(Tim Slagle) #7

yep. this would work much better.


(Vishal Kumar) #8

Problem is - I’m trying to fire off every 3 SECONDS. I remember seeing somewhere in the documentation that the schedule function cannot do any quicker than per-minute tasks. Is there any work-around?


(Vishal Kumar) #9

Swanny,

For whatever reason (knock on wood!), 8 seconds seems to be a sweet spot for me too. Thanks so much for the advice!


(Tim Slagle) #10

I would recommend not polling anything more often then 1 minute… This is abuse of the cloud and part of the reason why STs has latency issues. The more people that call things more often then 1 minute the more often we will see delayed STs events and the like.

Do you really need to check the status of a smart switch every 3 seconds? Out of the 259,000 calls you’ll do daily how often will you get a delta change for the state?

Change it to every minute, the cloud would appreciate it! And so would the STs customers for not slowing down app processing.


(Joel T) #11

Tim, that’s great and all, but some devices that humans interact with really do change more often than 1 minute. Even my 1 minute actions are getting ?canceled? after just one or 2 cycles.

I have a Enerwave RSM2 zwave device that is a really cost-effective option for controlling two lighting circuits. It has toggle inputs for both circuits too, so you can hook it to existing light switches for manual control as well. It sends a BasicReport when circuit 1 is toggled manually, but doesn’t do the same for circuit 2. Sure, the device has a weakness, but can’t ST work around that? Sure, I’ll use runIn() to trigger a manual refresh on the device states (which I know how to do, and works reliably)… oh wait, runIn doesn’t actually work that well.

One of devices is on my garage overhead lights. They get left on accidentally all the time, and I’d like to setup a “left on for x minutes” notification so I can decide if I want to turn them off. But if runIn doesn’t run deterministically, the whole user experience breaks down.

Weren’t they working on moving some processing to the hub itself? runIn() for device polling seems like an awfully good candidate for that.


[RELEASE] 5-2 Day Programmable Thermostat Scheduler (Weekday, Weekend) with Remote Temperature Sensor for each Schedule
(Tim Slagle) #12

I’d recommend a chron schedule and not a runIn.

these are only allowed every 1 minute and don’t stack so it shouldn’t be “cancelled” This is going to be the fastest you can fire something off without it being cancelled. Unfortunately the stability of the environment is a priority in this case.

put this in your app inistialization

schedule(CHRONEXPRESSION, poll/ANOTHER APP VARIABLE)