Return data from parent app to child driver

im moving this code from ST but in HE its not return the data
So this line in the driver sets the alarm and gets the response

def data = parent.ArmDisRef(mode)

log.debug "POSTCMD $data"

this processes it in the app and returns it to drive which called it, it work fine in ST, but in HE it arms/disarms fine but never returns the message details from the http just null

log.debug "Incoming Mode CMD ${mode.value} "`
    def paramsMode = [
        			uri: "https://mob.yalehomesystem.co.uk/yapi/api/panel/mode/",
        			body: [area: 1, mode: "${mode.value}"],
        			headers: ['Authorization' : "Bearer ${state.Token}"],
        			requestContentType: "application/x-www-form-urlencoded",
        			//in event of error// requestContentType: "application/json",
        			contentType: "application/json"
        	]
        try{
    	httpPost(paramsMode) {	response ->
        	def respstatus = response?.status
            def respdata = response?.data
    		if (respstatus == 200){
                def respmsg = response?.data?.message
                if (state.errorCount != 0) {
				state.errorCount = 0
			}
            if (state.currentError != null) {
				state.currentError = null
            }
            log.info "Mode $mode - '$respstatus' - '$respmsg' $respdata" 
            if (respmsg != 'OK!'){
               	send("Alarm mode change to '$mode' issue, message $respmsg") //if door left open
            }
         return respdata   
		}
		else { //response status not 200
        	log.error "Error in MODE '$respstatus' to $mode, ${state.currentError} - $respdata"
			state.currentError = "error mode pannel $respstatus - $respdata"
			respdata = 'error'
            errorhand("Error Arm/Dis/Ref NOT 200")
		}
        
/*        def isChild = getChildDevice('RF:YalePan1')
            	if (isChild) {
                    log.info "Sending status of '${respdata}" 
                	isChild.datain(respdata)
                }
*/        
		return respdata // this isnt returning data to driver
	}
    }
    catch (e){
    	log.error "Error arm/dis/Ref: ${e}, ${e?.message}"
        state.currentError = e?.message
        errorhand("Error Arm/Dis/Ref Catch")
    }
}

any tips?

In general, when pasting code on the forum it is helpful if you use the code "pre-format" button.
image
This will prevent Discourse from changing any of the formatting for your code, making it next to impossible to read.

def ArmDisRef(mode){
log.debug "Incoming Mode CMD ${mode.value} "
def paramsMode = [
		uri: "https://mob.yalehomesystem.co.uk/yapi/api/panel/mode/",
		body: [area: 1, mode: "${mode.value}"],
		headers: ['Authorization' : "Bearer ${state.Token}"],
		requestContentType: "application/x-www-form-urlencoded",
		//in event of error// requestContentType: "application/json",
		contentType: "application/json"
]
try{
httpPost(paramsMode) {	response ->
	def respstatus = response?.status
    def respdata = response?.data
	if (respstatus == 200){
        def respmsg = response?.data?.message
        if (state.errorCount != 0) {
			state.errorCount = 0
		}
        if (state.currentError != null) {
			state.currentError = null
        }
        log.info "Mode $mode - '$respstatus' - '$respmsg'" // $respdata" 
        return respdata
        
        if (respmsg != 'OK!'){
           	send("Alarm mode change to '$mode' issue, message $respmsg") //if door left open
        }   
	}
	else { //response status not 200
    	log.error "Error in MODE '$respstatus' to $mode, ${state.currentError} - $respdata"
		state.currentError = "error mode pannel $respstatus - $respdata"
		respdata = 'error'
        errorhand("Error Arm/Dis/Ref NOT 200")
        return respdata   

	}

Is it possible to "return" data from a parent app to a driver?

How are you calling to the parent app within the device? Are you broadcasting an event it subscribes to?

This driver you posted above is doing an HTTP call, not sending data to a parent app. So, I am confused how your example relates to your question. If this method in the driver is being called from a parent app, you would have to show how that is being called.

But also, that would be in the wrong direction. You are asking for data to be return FROM the parent. In this case, the parent is the one that would be waiting for the return. Not the child device. Do you have an example of what you mean?

this is the call, but the return "def data" is null

Can I ask a couple of questions that might make things a lot easier?

#1, why are you calling this from a device? You can just as easily subscribe to the mode in an app and handle this all within the app. Conversely, your device could just as easily make the HTTP call itself.

I believe this combo is using the service manager model from ST because you can't make internet HTTP calls from a DTH. But Hubitat has not such restrictions. You can make that HTTP call directly from the device.

I think doing it either of those ways would be easier.

the app pulls in and creates all the child contact sensor,
to reduce polling (and because one call to yale brings in the data) the app makes one call and then pushes the data to all the children (instead of every contact sensor making a call to yale)
only 1 driver makes (to arm/disarm) sends a request to the app.
also my log in details and token are only used in the app

Tagging @mike.maxwell and @chuck.schwer, the Hubitat experts on the platform.

You can pull data from a parent app within a child device... Here's an example..

In the driver...

	// Get the token & secret from the parent
	def connIP = parent.getPref("proxyIP")
	def connPort = parent.getPref("proxyPort")

And in the App:

def getPref(setting) {return settings."${setting}"}

That little helper function can be used to pull any setting from the parent app into the driver.. I dont' recommend the practice as a matter of course since settings can be stored in devices too.. However it does get around the 256 character limit on string settings in device drivers. :slight_smile:

1 Like

That is what he's doing. The function ArmDisRef is defined in the parent app.

@mark.cockcroft, have you tried changing the response to a constant to just see if anything can be returned or if there is something wrong with your structure?
If you did:

def ArmDisRef(mode){
     def response = "RETURNING"
     return response
}

And in your driver just log the response out you'd at least see if it was the return that was the problem or the HTTP call in the app.

Like this?

def ArmDisRef(mode){
log.debug "Incoming Mode CMD ${mode.value} "
def response = "Ryan suggestion?"
     return response
def paramsMode = [
		uri: "https://mob.yalehomesystem.co.uk/yapi/api/panel/mode/",
		body: [area: 1, mode: "${mode.value}"],
		headers: ['Authorization' : "Bearer ${state.Token}"],
		requestContentType: "application/x-www-form-urlencoded",
		//in event of error// requestContentType: "application/json",
		contentType: "application/json"
]
try{
httpPost(paramsMode) {	response ->
	def respstatus = response?.status
def respdata = response?.data
	if (respstatus == 200){
    def respmsg = response?.data?.message
    if (state.errorCount != 0) {
			state.errorCount = 0
		}
    if (state.currentError != null) {
			state.currentError = null
    }
    log.info "Mode $mode - '$respstatus' - '$respmsg'" // $respdata" 
    return respdata
    
    if (respmsg != 'OK!'){
       	send("Alarm mode change to '$mode' issue, message $respmsg") //if door left open
    }   
	}
	else { //response status not 200
	log.error "Error in MODE '$respstatus' to $mode, ${state.currentError} - $respdata"
		state.currentError = "error mode pannel $respstatus - $respdata"
		respdata = 'error'
    errorhand("Error Arm/Dis/Ref NOT 200")
    return respdata   

	}

well, you don't have a closure to close out the method at the end. You're missing a close curly bracket.

But you'd also want to modify the driver to just log the response. I don't see what is in the driver code after your call to ArmDisRef.

yet it worked, trew a wobble becase it cudnt handle the response but it retuned it the the driver
image

full section

def postcmd(mode){
	log.trace "postcmd outgoing Mode CMD $mode "
    def data = parent.ArmDisRef(mode)
    log.info "POSTCMD $data"
    def dmsg = ''
    if (data != "error"){
    	dmsg = data?.message
    }
    else {
    	dmsg = data
    }
	if (dmsg == 'OK!'){
    	state.errorCount = 0
    	if (mode == 'arm'){
        	state.modes = "armedAway"
            state.lock = "unlocked"
            state.switch = "on"
            state.alarm = "both"
        }
        else if (mode == 'disarm'){
        	state.modes = "disarm"
            state.lock = "unlocked"
            state.switch = "off"
            state.alarm = "off"
        }
        else if (mode == 'home'){
        	state.modes = "armedStay"
            state.lock = "locked"
            state.switch = "off"
            state.alarm = "siren"
        }
    }
/*	else {
    	state.errorCount = state.errorCount +1
    	state.modes = "disabled"
        state.alarm = "disabled"
    }
    log.info "Mode Change state is ${state.modes}, $dmsg, errors are ${state.errorCount}"
	sendEvent(name: "modes", value: state.modes, displayed: true, descriptionText: "Mode Change to ${state.modes} - $dmsg") //isStateChange: false,
    sendEvent(name: "lock", value: state.lock, displayed: false) //isStateChange: false,
	sendEvent(name: "switch", value: state.switch, displayed: false) //isStateChange: false,
    sendEvent(name: "alarm", value: state.alarm, displayed: false, descriptionText: "Mode Change to ${state.modes} - $dmsg") //isStateChange: false,
*/
}

app

def ArmDisRef(mode){
	log.trace "Incoming Mode CMD ${mode.value} "
    //def responsetest = "Ryan suggestion?"
    // return responsetest
	def paramsMode = [
			uri: "https://mob.yalehomesystem.co.uk/yapi/api/panel/mode/",
			body: [area: 1, mode: "${mode.value}"],
			headers: ['Authorization' : "Bearer ${state.Token}"],
			requestContentType: "application/x-www-form-urlencoded",
			//in event of error// requestContentType: "application/json",
			contentType: "application/json"
	]
    try{
	httpPost(paramsMode) {	response ->
    	def respstatus = response?.status
        def respdata = response?.data
		if (respstatus == 200){
            def respmsg = response?.data?.message
            if (state.errorCount != 0) {
				state.errorCount = 0
			}
            if (state.currentError != null) {
				state.currentError = null
            }
            log.info "Mode $mode - '$respstatus' - '$respmsg'" // $respdata" 
            return respdata
            
            if (respmsg != 'OK!'){
               	send("Alarm mode change to '$mode' issue, message $respmsg") //if door left open
            }   
		}
		else { //response status not 200
        	log.error "Error in MODE '$respstatus' to $mode, ${state.currentError} - $respdata"
			state.currentError = "error mode pannel $respstatus - $respdata"
			respdata = 'error'
            errorhand("Error Arm/Dis/Ref NOT 200")
            return respdata   

		}
               
		return respdata // this isnt returning data to driver
	}
    }
    catch (e){
    	log.error "Error arm/dis/Ref: ${e}, ${e?.message}"
        state.currentError = e?.message
        errorhand("Error Arm/Dis/Ref Catch")
    }
}

So, the problem isn't in the driver...it's in your app. Something in the HTTP call is not being parsed correctly, that's why it's returning nothing. There's nothing to return.

this line works
prior to the early retun we added

this was the orignal (in st)
the other two above i added testing

image

just return response.data if that's what respdata is being set to. have you confirmed that there is something in response.data to return?

I think I see what's happening here.. Unfortunately the code formatting is making it difficult to read..

You've got a scoping issue. You are returning respdata from within the httpPost enclosure.. That only returns from the enclosure, not your ArmDisRef method. Since nothing is captuing the return data, there's nothing to return.

The simple fix is to move "def respdata" outside of the enclosure and return it at the end of the method.

1 Like

You mean after you close out the try/catch, right? (Just checking to make sure I'm following you, not questioning if you're right. Self-taught programmer so sometimes the jargon gets me confused.)