Bluesound Art URI

Hi Guys,

I have created Driver for Bluesound on Hubitat. Bluesound works fine, everything I need is there. But a problem arose when I imported it on the Home Remote. All Audio Data Tracks do not appear, from Album Art URI to Title.

Can anyone help me to solve this problem?

Thank you.

What version of the Designer are you using?

Make sure you have the latest version installed. AudioTrackData was added to the Hubitat integration in version 4.3. Assuming the Bluesound data is formatted like it is for Echo then it should work.

The Home Remote Ver. 4.4.1.0

That must mean the are reporting that data differently.

The Home Remote reads “trackData” from Hubitat’s MusicPlayer capability.
https://docs.hubitat.com/index.php?title=Driver_Capability_List#MusicPlayer

I suggest you look at the source for your Bluesound driver.

Can anyone help me correct the driver I made?

This driver that I made cannot display Audio Track Data on the Home Remote.

This is the code, I made it on Hubitat. :

/*

*/

metadata
{
    definition(name: "Bluesound Node2i", namespace: "putudhony88", author: "putudhony88", importUrl: "")
    {
        capability "AudioVolume"
        capability "Initialize"
        capability "MediaInputSource"
        capability "Refresh"
        capability "MusicPlayer"

        command "executeCommand", ["command"]
        command "repeat"
        command "shuffle"
        command "bluetooth"
        command "hdmi"
        command "spotify"
        
        command "preset1"
        command "preset2"
        command "preset3"
        command "preset4"
        command "preset5"
        command "preset6"
        
        command "addZoneSlave", ["slaveIP"]
        command "removeZoneSlave", ["slaveIP"]
        
        attribute "trackArt", "string"
        
    }
    

}

preferences
{
    section
    {
        input "IP_address", "text", title: "IP address of Bluesound unit", required: true
        input "refreshInterval", "number", title: "Polling refresh interval in seconds", defaultValue: 60
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
    }
}

def logDebug(msg)
{
    if (logEnable)
    {
        log.debug(msg)
    }
}

def installed()
{
    sendEvent(name: "supportedInputs", value: '{"HDMI", "Bluetooth", "Spotify"}')
    initialize()
}

def initialize()
{
    refresh()
}

def refresh()
{
    unschedule(refresh)
    
    def status = httpGetExec("Status")
    
    if(status)
    {
        events = [[:]]
        events += [name: "volume", value: status.volume.toInteger()]
        events += [name: "mute", value: (status.mute.toInteger() == 1) ? "muted" : "unmuted"]
        events += [name: "status", value: status.state]
        events += [name: "trackData", value: status.streamUrl]
        events += [name: "trackDescription", value: "${status.title1} - ${status.artist} - ${status.album}"]
        events += [name: "trackArt", value:"<img src=\"${status.currentImage}\">"]
        
        
        switch(status.inputId)
        {
            case "input4":
                events += [name: "MediaInputSource", value: "HDMI"]
                break
            case "Spotify":
                events += [name: "MediaInputSource", value: "Spotify"]
                break
            case "input5":
                events += [name: "MediaInputSource", value: "Bluetooth"]
                break
        }
        
        
        events.each
        {
            sendEvent(it)
        }        
    }
       
    runIn(refreshInterval ?: 60, refresh)
}

def updated()
{
    installed()
}

def uninstalled()
{
    unschedule()
}

def play()
{
    executeCommand("Play")
}

def pause()
{
    executeCommand("Pause")
}

def stop()
{
    executeCommand("Stop")
}

def nextTrack()
{
    executeCommand("Skip")
}

def previousTrack()
{
    executeCommand("Back")
}

def mute()
{
    executeCommand("Volume?mute=1")
}

def unmute()
{
    executeCommand("Volume?mute=0")
}

def setVolume(volumelevel)
{
    logDebug("setting volume to: $volumelevel")
    
    vol = volumelevel.toInteger()    
    vol = (vol < 0) ? 0 : (vol > 100) ? 100 : vol
    
    executeCommand("Volume?level=${vol.toString()}&tell_slaves=off")
}

def volumeDown()
{
    executeCommand("Volume?db=-1")
}

def volumeUp()
{
    executeCommand("Volume?db=1")
}

def playTrack(trackuri)
{
    executeCommand("Play:${trackuri}")
}

def restoreTrack(trackuri)
{
    playTrack(trackuri)
}

def resumeTrack(trackuri)
{
    playTrack(trackuri)
}

def repeat()
{
    executeCommand("Repeat?state=1")  
}

def shuffle()
{
    executeCommand("Shuffle?state=1")  
}

def bluetooth()
{
    executeCommand("Play?url=Capture%3Abluez%3Abluetooth")  
}

def hdmi()
{
    executeCommand("Play?url=Capture%3Ahw%3A2%2C0%2F1%2F25%2F2%2Finput4")  
}

def spotify()
{
    executeCommand("Play?url=Spotify%3Aplay")  
}

def addZoneSlave(slaveIP)
{
    executeCommand("AddSlave?slave=${slaveIP.toString()}&port=11000") 
}

def removeZoneSlave(slaveIP)
{
    executeCommand("RemoveSlave?slave=${slaveIP.toString()}&port=11000") 
}

def setInputSource(inputName)
{
    switch(inputName)
    {
        case "HDMI":
            hdmi ()
            break
        case "Spotify":
            spotify()
            break
        case "Bluetooth":
            bluetooth()
            break
    }
    sendEvent(name: "mediaInputSource", value: status.service)
}

def preset1()
{
    executeCommand("Preset?id=1")
}

def preset2()
{
    executeCommand("Preset?id=2")
}

def preset3()
{
    executeCommand("Preset?id=3")
}

def preset4()
{
    executeCommand("Preset?id=4")
}

def preset5()
{
    executeCommand("Preset?id=5")
}

def preset6()
{
    executeCommand("Preset?id=6")
}

def scaleBluesoundToPercent(volumeLevel)
{
    def percVol = ((volumeLevel.toInteger() + 90) * 100/10).toInteger()
    percVol = (percVol >= 0) ? ((percVol <=100) ? percVol : 100) : 0
    return percVol
}

def scalePercentToBluesound(volumeLevel)
{
    def neetsVol = (volumeLevel.toInteger() * 10/100).toInteger() - 90
    neetsVol = (neetsVol >= -90) ? ((neetsVol <= 0) ? neetsVol : 0) : -90
    return neetsVol
}

def executeCommand(command, doRefresh = true)
{
    res = httpGetExec(command)
    
    if((null != res) && doRefresh)
    {
        runInMillis(100, refresh)
    }
    
    return res
}

def getBaseURI()
{
    return "http://" + IP_address + ":11000/"
}

def httpGetExec(suffix)
{
    logDebug("httpGetExec(${suffix})")

    try
    {
	    def result
        def getString = getBaseURI() + suffix
        httpGet(getString.replaceAll(' ', '%20'))
        { resp ->
            if (resp.data)
            {
                logDebug("resp.data = ${resp.data}")
                result = resp.data
            }
        }		
	        return result
    }
    catch (Exception e)
    {
        logDebug("httpGetExec() failed: ${e.message}")
    }

}

Thank you

I think it’d probably be more helpful to share the JSON like Christopher did.

Also, when posting code or JSON, please use the 3 ticks ` at the beginning & the end so the code is easier to read.

Is it true like this?

if wrong can you give me a hint?

No, that’s XML. It’s going to be JSON. Look at post above from Christopher that I just shared with you.

Here’s instructions on how to get the JSON.

https://docs.hubitat.com/index.php?title=Maker_API

{"id":"1152","name":"Bluesound Node 2i","label":"Jacuzzi - Bluesound Node 2i","type":"Bluesound Node2i","attributes":[{"name":"mute","currentValue":"unmuted","dataType":"ENUM","values":["unmuted","muted"]},{"name":"supportedInputs","currentValue":"{\"HDMI\", \"Bluetooth\", \"Spotify\"}","dataType":"JSON_OBJECT"},{"name":"trackDescription","currentValue":"Lupino - Magnofield - Lupino","dataType":"STRING"},{"name":"status","currentValue":"stream","dataType":"STRING"},{"name":"trackArt","currentValue":"<img src=\"https://i.scdn.co/image/ab67616d0000b273b9413ba2720adb83a46f82c2\">","dataType":"STRING"},{"name":"trackData","currentValue":"Spotify:spotify_pcm01:pcm/44100/16/2/55","dataType":"JSON_OBJECT"},{"name":"level","currentValue":null,"dataType":"NUMBER"},{"name":"mute","currentValue":"unmuted","dataType":"ENUM","values":["unmuted","muted"]},{"name":"volume","currentValue":65,"dataType":"NUMBER"},{"name":"mediaInputSource","currentValue":null,"dataType":"STRING"}],"capabilities":["MusicPlayer",{"attributes":[{"name":"status","dataType":null},{"name":"level","dataType":null},{"name":"trackDescription","dataType":null},{"name":"trackData","dataType":null},{"name":"mute","dataType":null}]},"Refresh","Initialize","AudioVolume",{"attributes":[{"name":"volume","dataType":null},{"name":"mute","dataType":null}]},"MediaInputSource",{"attributes":[{"name":"supportedInputs","dataType":null},{"name":"mediaInputSource","dataType":null}]}],"commands":["addZoneSlave","bluetooth","executeCommand","hdmi","initialize","mute","nextTrack","pause","play","playText","playTrack","preset1","preset2","preset3","preset4","preset5","preset6","previousTrack","refresh","removeZoneSlave","repeat","restoreTrack","resumeTrack","setInputSource","setLevel","setTrack","setVolume","shuffle","spotify","stop","unmute","volumeDown","volumeUp"]}

The current value of trackData in the JSON you just shared is:

Spotify:spotify_pcm01:pcm/44100/16/2/55

That is not valid JSON nor does it have the information we want. Someone is going to have to revise the source code for that driver to populate trackData with JSON. They are using a custom attribute “trackArt”.

…your other option is to just add “trackArt” as a custom attribute on the Home Remote Device object. The only thing there is, it’s not going to be part of AudioTrackData so the default MediaPlayer XAML templates aren’t going to work for you. You’ll have to customize them to point to your custom attribute.

What do you mean here?

Yes. Now you can access the album art by using @Device.trackArt

Sorry still can’t.

I have binding.

Jacuzzi Binding

That should work. Bind it to a Label & make sure you see the URL when you run the simulator.

It worked Bill, you’re amazing. I couldn’t because I did an image search. I’ve changed it

Thank you very much

1 Like