Device Type and Rest


(Chris Burton) #1

Here is the situation. I’m too cheap to buy Sonos, so I’ve set up my Subsonic instance to play to PulseAudio to a couple Raspberry PIs around the house. What happens is I can go to the Subsonic web interface and control the jukebox then the sound comes out from the RPis like magic. So I was thinking, wouldn’t it be great to do this from SmartThings so that I could then have the music fade on in the morning, or out at night. Or have it turn on when I’m away so that the dogs have something to listen to.

I will say that I am new to Groovy and SmartThings device types, but not to coding. I’ve been through this forum and a number of available projects on the Internet trying to find a fix.

I’ve seen multiple topics on the subject, and I almost have it. I am stuck with the Base64 decoding that needs to occur. I’ve borrowed heavily from this project.

Here is the offending code:

if (msg.headers) {
    // parse HTTP response headers
    def headers = new String(msg.headers.decodeBase64())
    def parsedHeaders = parseHttpHeaders(headers)
    log.debug parsedHeaders
    //TRACE("parsedHeaders: ${parsedHeaders}")
    if (parsedHeaders.status != 200) {
        log.error "Server error: ${parsedHeaders.reason}"
        return null
    }

    // parse HTTP response body
    if (!msg.body) {
        log.error "HTTP response has no body"
        return null
    }

	/*if (!msg.xml) {
        	log.error "No XML Returned"
            return null
    }*/
    
    def body = new String(msg.body.decodeBase64())
    log.debug body
    def slurper = new XmlSlurper()
    def sonic = slurper.parseText(body)
    
    log.debug sonic
} 


...


def test() {
log.debug "Executing 'test'"
// TODO: handle 'test' command
//TRACE("test()")
//STATE()

setNetworkId(confIpAddr, confTcpPort)
return apiGet("/rest/ping.view")
}

// Sets device Network ID in 'AAAAAAAA:PPPP' format
private String setNetworkId(ipaddr, port) { 
//TRACE("setNetworkId(${ipaddr}, ${port})")

def hexIp = ipaddr.tokenize('.').collect {
    String.format('%02X', it.toInteger())
}.join()

def hexPort = String.format('%04X', port.toInteger())
device.deviceNetworkId = "${hexIp}:${hexPort}"
log.debug "device.deviceNetworkId = ${device.deviceNetworkId}"
}

private apiGet(String path) {
    //TRACE("apiGet(${path})")

def headers = [
    HOST:       "${confIpAddr}:${confTcpPort}",
    Accept:     "*/*"
]

def httpRequest = [
    method:     'GET',
    path:       path,
    headers:    headers,
    query: [u: settings.username, p: settings.password, v: "1.12.0", c: "smartthings"]
]

return new physicalgraph.device.HubAction(httpRequest)
}

The response I am getting in the log is this:

70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:23 PM: debug
70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:23 PM: debug 

70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:23 PM: debug [protocol:HTTP/1.1, status:200, reason:OK]
70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:23 PM: debug Parsing 'index:01, mac:F0DEF1FA3344, ip:C0A80095, port:0FC8, headers:SFRUUC8xLjEgMjAwIE9LDQpBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW46ICoNCkNvbnRlbnQtVHlwZTogdGV4dC94bWw7IGNoYXJzZXQ9dXRmLTgNCkV4cGlyZXM6IFRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UDQpTZXQtQ29va2llOiBKU0VTU0lPTklEPTE0MTkwbDRod2doN3c7UGF0aD0vDQpDb250ZW50LUxlbmd0aDogMTI1DQpTZXJ2ZXI6IEpldHR5KDYuMS54KQ==, body:PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN1YnNvbmljLXJlc3BvbnNlIHhtbG5zPSJodHRwOi8vc3Vic29uaWMub3JnL3Jlc3RhcGkiIHN0YXR1cz0ib2siIHZlcnNpb249IjEuMTIuMCIvPgo='
70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:22 PM: debug device.deviceNetworkId = C0A80095:0FC8
70039528-8b7f-4c08-8f09-5375e6189bbc 8:56:22 PM: debug Executing 'test'

Basically saying that the headers are decoding correctly, but not the body. I know I am close, because when I copy the body segment that is Base 64 to a different decoder, it decodes correctly.

Please help if you can.


(Patrick Stuart [@pstuart]) #2

It is possible your body message is getting truncated but it does decode properly to this:

<?xml version="1.0" encoding="UTF-8"?>

try in your parse to just log.debug msg.body and see if that returns the base64 full code.

It could be parsing properly, just not showing up in the IDE. So just parse it as if it is there.


(Chris Burton) #3

Score!! What a pain in the tuckus.

The new code at the bottom of the parse function looks like this:

 def encbody = msg.body
 def body = new String(encbody.decodeBase64())
 def statusrsp = new XmlSlurper().parseText(body)
    
 def status = statusrsp.@status.text()
 log.debug "Status '${status}'"

Thanks so much!