Help! SmartApp works perfectly in Simulator, but not at all when installed from mobile app

I have created three SmartApps in the IDE, and published them “For me”. When I use the Simulator to install them for my home hub–using real sensor data from my home sensors–they work great. But if I instead go into the ST classic app, and install them from there, using the exact same Preferences, only one out of the three actually works.

The one that works is scheduled; it runs at the same time every day. The two that don’t work, aren’t scheduled–they’re meant to be kicked off by sensor events. And in the Simulator, they are.

To throw another wrench in the works: I was using the Android app to install these SmartApps initially, and running into the problem above. Then at one point I grabbed my wife’s iPhone and used that to install the apps, and they worked–once. When I had to make any updates or changes, they stopped working.

As you can imagine, I’m confused and bewildered. I have to have these apps working by tomorrow, and installing them from the IDE isn’t a viable option, because I have to have multiple instances of these apps running under different names (which is not possible in the Simulator).

In the interest of expedience, I’ve posted the code of one of the apps which works only in the Simulator, below. (Icon URLs have been removed because “New users are only able to put two links in a post.”)

/**

  • Possible Bathroom Incident
  • Copyright 2019
  • Author: Me
  • Date: 2019-10-10
  • Get notified if the bathroom door is closed and there has been no motion for some period of time.
    */

definition(
name: “Possible Bathroom Incident”,
namespace: “smartthings”,
author: “Me”,
description: “Get notified if the bathroom door is closed and there has been no motion for some period of time.”,
category: “Health & Wellness”,
)

preferences {
section(“Who are you checking on?”) {
input “person1”, “text”, title: “Loved one’s name or title?”, required: true
}
section(“If this bathroom door is closed…”) {
input “contact1”, “capability.contactSensor”, title: “Choose a door contact sensor.”, required: true
}
section("…and there is no motion on these sensors…") {
input “motion1”, “capability.motionSensor”, title: “Choose a motion sensor.”, required: true, multiple: true
}
section("…for this many minutes…") {
input “noMotionThreshold”, title: “Threshold for no motion?”, description: “Number of minutes”, required: true
}
section("…then alert the following people…") {
input(“recipients”, “contact”, title: “People to notify?”, description: “Send notifications to…”) {
input “phone1”, “phone”, title: “Phone number?”, required: true, multiple: true
}
}
}

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

def updated() {
log.debug “Updated with settings: ${settings}”
unsubscribe()
initialize()
}

def initialize() {
state.active = 0
subscribe(contact1, “contact.open”, bathroomDoorOpened)
subscribe(contact1, “contact.closed”, bathroomDoorClosed)
subscribe(motion1, “motion.active”, bathroomActive)
subscribe(motion1, “motion.inactive”, bathroomInactive)
//sendPush(“Initialized.”)
}

def bathroomDoorOpened(evt) {
state.status = “doorOpen”
unschedule(“sendMessage”)
log.debug “bathroomDoorOpened. Status: $state.status”
//sendPush(“bathroomDoorOpened. Status: $state.status. Unscheduled sendMessage.”)
}

def bathroomDoorClosed(evt) {
// Skip past the Awaiting Motion state and go straight to Motion Confirmed.
// The Awaiting Motion state made it possible for an incident to not be detected
// if there was an unbroken stream of motion from the moment the subject entered the bathroom.
//state.status = “doorClosedAwaitingMotion”
state.status = “doorClosedMotionConfirmed”
log.debug “bathroomDoorClosed. Status: $state.status”
//sendPush(“bathroomDoorClosed. Status: $state.status”)
//runIn(60, checkFirstMinuteForMotion)
//log.debug “runIn(60, checkFirstMinuteForMotion)”
}

// No longer used. If there is an unbroken stream of motion from the moment the door is closed,
// this function doesn’t reveal any ‘active’ events since the door was closed.
/**
def checkFirstMinuteForMotion() {
def sinceTime = new Date(now() - 60000) // One minute ago.
log.debug “sinceTime: ${sinceTime}”
if(noRecentMotion(sinceTime) == false) {
if(state.status == “doorClosedAwaitingMotion”) {
state.status = “doorClosedMotionConfirmed”
log.debug “Motion detected during first minute in bathroom. Status: $state.status”
sendPush(“Motion detected during first minute in bathroom. Status: $state.status”)
} else {
log.debug “Motion not detected during first minute in bathroom. Status: $state.status”
sendPush(“Motion not detected during first minute in bathroom. Status: $state.status”)
}
}
}
*/

def bathroomActive(evt) {
log.debug “bathroomActive. Status: $state.status”

// If doorClosedMotionStopped, stop the timed message--the person is moving around in the bathroom.
if (state.status == "doorClosedMotionStopped") {
	state.status = "doorClosedMotionConfirmed"
	unschedule("sendMessage")
	log.debug "Motion detected in bathroom, disarmed. Status: $state.status"
	//sendPush("Motion detected in bathroom, disarmed. Status: $state.status")
}

// If doorClosedAwaitingMotion, confirm that motion has occurred--the bathroom is occupied.
if (state.status == "doorClosedAwaitingMotion") {
	state.status = "doorClosedMotionConfirmed"
	log.debug "Motion detected in bathroom, confirmed occupied. Status: $state.status"
	//sendPush("Motion detected in bathroom, confirmed occupied. Status: $state.status")
}

// If doorOpen, do nothing--the person may be moving freely in and out of the bathroom.
// If doorClosedMotionConfirmed, do nothing--the person is still in the bathroom.

}

def bathroomInactive(evt) {
log.debug “bathroomInactive. Status: $state.status”

// If doorClosedMotionConfirmed, start the timer.
if (state.status == "doorClosedMotionConfirmed") {
	state.status = "doorClosedMotionStopped"
	def threshold = noMotionThreshold
	def delay = threshold.toInteger() * 60
	log.debug "runIn($delay)"
	runIn(delay, sendMessage)
	log.debug "Motion stopped in bathroom, arming. Status: $state.status"
	//sendPush("Motion stopped in bathroom, arming. Status: $state.status")
}

// If doorOpen, do nothing--nobody is in the bathroom.
// If doorClosedAwaitingMotion, do nothing--the bathroom door may be closed with nobody inside.
// If doorClosedMotionStopped, do nothing--let the timer keep running down.

}

def sendMessage() {
def sinceTime = getSinceTime()
if(noRecentMotion(sinceTime)) {
def person = person1 ?: “your loved one”
def threshold = noMotionThreshold
def msg = “ALERT: The bathroom door is closed, and there has been no motion in the bathroom for {threshold} minutes at {person}'s place.”
log.debug msg

	if (location.contactBookEnabled) {
		sendNotificationToContacts(msg, recipients)
	} else {
		if (phone1) {
			sendSms(phone1, msg)
            //sendPush("Sent SMS.")
		}
		sendPush(msg)
	}
} else {
	log.debug "There has been recent motion detected, not sending alert."
	//sendPush("There has been recent motion detected, not sending alert.")
}
state.status = null

}

private noRecentMotion(sinceTime) {
log.debug “noRecentMotion called with parameter {sinceTime}." sendPush("noRecentMotion called with parameter {sinceTime}.”)
if(motion1) {
def motionEvents = motion1.eventsSince(sinceTime)
log.trace “Found ${motionEvents?.size() ?: 0} motion events”
if (motionEvents.find { it.value == “active” }) {
log.debug “There have been recent ‘active’ events”
//sendPush(“There have been recent ‘active’ events.”)
return false
} else {
log.debug “There have not been any recent ‘active’ events”
//sendPush(“There have not been any recent ‘active’ events.”)
return true
}
} else {
log.debug “Motion sensor not enabled”
//sendPush(“Motion sensor not enabled.”)
return true
}
}

private getSinceTime() {
// I believe date math is done in milliseconds.
def threshold = noMotionThreshold
def thresholdMilliseconds = threshold.toInteger() * 60000

return new Date(now() - thresholdMilliseconds)

}