openHAB integration to Spotify Web Connect API (player)


(Christian Raid) #164

Hello Guy´s
i need help at this step. I am a newbie in openhab
How and where do i check that the spotify_auth_code is set in OpenHab
How and where do i Set the REDIRECT_URI in spotify.py to the right value
How do i use the spotify.py


(Frederick) #165

Thanks for the hard work, however i guess the spotify.py is for python 2x do any of you have the equivalent for python 3?


(Alan Fenwick) #166

Never mind - bodged shuffle functionality myself

Shuffle on is:
/usr/bin/python /etc/openhab2/scripts/spotify.py shuffle

Shuffle off is:
/usr/bin/python /etc/openhab2/scripts/spotify.py shuffleoff

Didn’t checkout any repos - will wait for an official release:
Here is my current script

Thisis an edit of one of the scripts referenced above - very little of it is my own code.
All credit to @pmpkk

#
# Use the Spotify Web Connect API using credentials auth code and tokens.
#

import json
import requests
import time
import urlparse
import sys
from myopenhab import openhab
from myopenhab import mapValues
from myopenhab import getJSONValue


#   API Gateway
ACCOUNT_URL = 'https://accounts.spotify.com/api/token'
API_ROOT_URL = 'https://api.spotify.com/v1/me/player/'
REDIRECT_URI = 'http://192.168.0.131:8080/static/spotify-auth.html'
RAW_ROOT_URL = 'https://api.spotify.com/v1/me/'
class spotify(object):
    """
    
    A wrapper for the Spotify Web Connect API

    https://developer.spotify.com/web-api/web-api-connect-endpoint-reference/

    """
    def __init__(self):

        self.debug = False 
        self.oh = openhab()

        self.client_id = self.oh.getState('spotify_client_id')
        self.client_secret = self.oh.getState('spotify_client_secret')

        self.access_token = self.oh.getState('spotify_access_token')
        self.refresh_token = self.oh.getState('spotify_refresh_token')
        self.token_issued = self.oh.getState('spotify_token_issued')
        self.token_expiry = self.oh.getState('spotify_token_expiry')

        if(self.token_expiry == "NULL"):
            self.refreshCredentials()
        if (self.access_token == "NULL"):
            self.generateCredentials()
        else:
            if (time.time() > float(self.token_expiry)):
                self.refreshCredentials()
      
    def generateCredentials(self):
        """
        Generate auth and refresh token for the very first time.
        """

        #   Send OAuth payload to get access_token
        payload = { 'code':self.oh.getState('spotify_auth_code'), 'client_id':self.client_id, 'client_secret':self.client_secret, 'redirect_uri':REDIRECT_URI, 'grant_type':'authorization_code' }
        
        print "-- Calling Token Service for the first time"

        try:
            r = requests.post(ACCOUNT_URL, data=payload, allow_redirects=False)

            if (self.debug): print r.headers
            if (self.debug): print r.json()
            resp = r.json()

            if(r.status_code == 200):
                access_token = resp['access_token']
                refresh_token = resp['refresh_token']
                expires_in = resp['expires_in']

                #   Set and Save the access token
                self.access_token = access_token
                self.refresh_token = refresh_token
                self.token_expiry = time.time() + float(expires_in)
                self.token_issued = time.strftime("%Y-%m-%dT%H:%M:%S")
                self.saveCredentials()
            else:
                print " -> Error getting token:" + str(resp)

        except:
            print " -> Error getting token:" + str(sys.exc_info()[1])

    def refreshCredentials(self):
        """
        If previous auth token expired, get a new one with refresh token.
        """

        #   Send OAuth payload to get access_token
        payload = { 'refresh_token':self.refresh_token, 'client_id':self.client_id, 'client_secret':self.client_secret, 'redirect_uri':REDIRECT_URI, 'grant_type':'refresh_token' }
        
        print "-- Calling Token Refresh Service"

        try:
            r = requests.post(ACCOUNT_URL, data=payload, allow_redirects=False)

            if (self.debug): print r.headers
            if (self.debug): print r.json()
            resp = r.json()

            if(r.status_code == 200):
                access_token = resp['access_token']
                expires_in = resp['expires_in']
                if('refresh_token' in resp): 
                    refresh_token = resp['refresh_token']
                    self.refresh_token = refresh_token

                #   Set and Save the access token
                self.access_token = access_token
                self.token_expiry = time.time() + float(expires_in)
                self.token_issued = time.strftime("%Y-%m-%dT%H:%M:%S")
                self.saveCredentials()
            else:
                print " -> Error refreshing token:" + str(resp)

        except:
            print " -> Error refreshing token:" + str(sys.exc_info()[1])

    def saveCredentials(self):
        """
        Save current tokens to the openhab.
        """

        self.oh.sendCommand('spotify_access_token',self.access_token)
        self.oh.sendCommand('spotify_refresh_token',self.refresh_token)
        self.oh.sendCommand('spotify_token_expiry',self.token_expiry)
        self.oh.sendCommand('spotify_token_issued',self.token_issued)

    def call(self, path, mode=None, payload=None):
        """
        Call the API at the given path.
        """
        print path 
        if path == "playlists" :
            print "playlists"
        else:  
            path  = "player/" + path 
        print RAW_ROOT_URL + path
        if (time.time() > self.token_expiry):
            self.refreshCredentials()
        headers = {"Authorization": "Bearer " + self.access_token, "Content-Type": "application/json" }
        if mode == "POST":
            r = requests.post(RAW_ROOT_URL + path,  headers=headers, data=payload)
            if(r.status_code != 202):
                print r.content
            return r.status_code
        elif mode == "PUT":
            r = requests.put(RAW_ROOT_URL + path,  headers=headers, data=payload)
            if(r.status_code != 202):
                print r.content
            return r.status_code
        else:
            r = requests.get(RAW_ROOT_URL + path,  headers=headers)
            if(r.status_code != 202 and r.status_code != 200 and r.status_code != 201 ):
                print r.content
            return r.json()

    def update(self):
        """
        Get a current player state.
        """
        print "-- Calling Service: Update"
        try:
            resp = self.call("")
            if (self.debug): print resp
            if ('item' in resp):

                self.oh.sendCommand('spotify_current_track', getJSONValue(resp, ['item','name']))
                self.oh.sendCommand('spotify_current_artist', getJSONValue(resp, ['item', 'artists', 0, 'name']))
                self.oh.sendCommand('spotify_current_cover', getJSONValue(resp, ['item', 'album', 'images', 1, 'url']))
                self.oh.sendCommand('spotify_current_duration', getJSONValue(resp, ['item', 'duration_ms']))
                self.oh.sendCommand('spotify_current_progress', getJSONValue(resp, ['progress_ms']))
                self.oh.sendCommand('spotify_current_progress', getJSONValue(resp, ['progress_ms']))
                self.oh.sendCommand('spotify_current_playing', mapValues(getJSONValue(resp, ['is_playing']), { 'True': 'ON', 'False': 'OFF' }))
                self.oh.sendCommand('spotify_current_device', getJSONValue(resp, ['device', 'name']))
                self.oh.sendCommand('spotify_current_volume', getJSONValue(resp, ['device', 'volume_percent']))
                self.oh.sendCommand('spotify_current_device_id', getJSONValue(resp, ['device', 'id']))

                print " -> Success"
            else:
                print " -> Item node missing from response :("
        except:
            print " -> Failure: ", sys.exc_info()[0]
            resp = ""

        return resp

    def volumeAdjust(self, adjustment = None):
        """
        Volume adjust by adjustment
        """
        print "-- Calling Service: Volume Up"
        try:
            vol = int(self.oh.getState('spotify_current_volume'))
            vol = int(round(vol/10)*10 + adjustment)
            if(vol>100): 
                vol = 100
            resp = self.volume(vol)
            
            if (self.debug): print resp
        except:
            print " -> VolumeUp Failure: ", sys.exc_info()[0]
            resp = ""

        return resp
   
    def volume(self, newVol = None):
        """
        Volume to newVol
        """
        print "-- Calling Service: Volume set"
        try:
            print "Volume To:" + str(newVol)
            resp = self.call("volume?volume_percent=" + str(newVol),"PUT" )
            self.oh.sendCommand('spotify_current_volume',newVol)
            if (self.debug): print resp
        except:
            print " -> VolumeDown Failure: ", sys.exc_info()[0]
            resp = ""

        return resp    
    
    

    def pause(self):
        """
        Pause player
        """
        print "-- Calling Service: Pause"
        try:
            resp = self.call("pause","PUT")
            self.oh.sendCommand('spotify_current_playing',"OFF")
            if (self.debug): print resp
        except:
            print " -> Pause Failure: ", sys.exc_info()[0]
            resp = ""

        return resp    
    
    def play(self, context_uri = None, new_device = None):
        """
        Resume player device
        """
        print "-- Calling Service: Play device"
         
        if (new_device is None or len(new_device)==0):
            action_url = "play"
            print "basic url match"
            print action_url
            if (context_uri is None):
                payload = {}
            else:
                payload = json.dumps({ 'context_uri': context_uri })
        else:
            if (context_uri is None):
                payload = json.dumps({ 'device_ids': [new_device] })
                action_url = ""
            else:
                payload = json.dumps({ 'context_uri': context_uri })
                action_url = "play?device_id=" + str(new_device)
        print payload
        print action_url

        try:
            resp = self.call(action_url,"PUT", payload = payload)
            if (self.debug): print resp
            self.update()
        except:
            print " -> Play Failure: ", sys.exc_info()[0]
            resp = ""

        return resp    

    def previous(self):
        """
        Skip to previous track
        """
        print "-- Calling Service: Previous"
        try:
            resp = self.call("previous","POST")
            if (self.debug): print resp
            self.update()  
        except:
            print " -> Previous Failure: ", sys.exc_info()[0]
            resp = ""

        return resp        

    def next(self):
        """
        Skip to next track
        """
        print "-- Calling Service: Next"
        try:
            resp = self.call("next","POST")
            if (self.debug): print resp
            self.update()
        except:
            print " -> Next Failure: ", sys.exc_info()[0]
            resp = ""

        return resp
    
    def shuffle(self):
        """
        Shuffle track
        """
        print "-- Calling Service: Shuffle"
        try:
            resp = self.call("shuffle?state=true","PUT")
            if (self.debug): print resp
            self.update()
        except:
            print " -> Shuffle Failure: ", sys.exc_info()[0]
            resp = ""

        return resp

    def shuffleoff(self):
        """
        Don't Shuffle track
        """
        print "-- Calling Service: Shuffle Off"
        try:
            resp = self.call("shuffle?state=false","PUT")
            if (self.debug): print resp
            self.update()
        except:
            print " -> Shuffle Failure: ", sys.exc_info()[0]
            resp = ""

        return resp

    def device_match(self, device_pick = None):
        """
        Identify device input type,(name, id or index).
        """
        print "-- Calling Service: devices_match"

        device_id_match=""
        index_test=""
        array_index=-1
#Dynamic check of id length against current id, with backup test if current id is null.
      
        try:
            if(device_pick):
                current_device_id = self.oh.getState('spotify_current_device_id')
                if( len(device_pick) == len(current_device_id) or len(device_pick) == 40):
                    array_index=1
                    print "id: ", device_pick        
                else:
                    if (device_pick.isdigit() and len(device_pick) < 3):
                        array_index=2
                        print "index: ", device_pick  
                    else:
                        print "name: ", device_pick
                        array_index=0           

        except:
            print " -> Failure: ", sys.exc_info()[0]          

        return array_index

    def playlists(self):
        """
        Get users recent playlists
        """
        print "-- Calling Service: get playlists"

        try:
            
            resp = self.call("playlists")
            if (self.debug): print resp
            self.oh.sendCommand('spotify_playlists', json.dumps(resp))

        except:
            print " -> Failure: ", sys.exc_info()[0]
            resp = ""
        
        return resp            

    def devices(self, name = None, idNum = None, devIndex = None):
        """
        Get a current player devices and helper function to play device.
        """
        print "-- Calling Service: get devices"
        exitStatus=" -> Success"
        selected_device=""
        
        if (name) or (idNum) or (devIndex): exitStatus = ""
        if (devIndex) : iIndex = int(devIndex)
        else: iIndex = -1
        arrayDesc=[name,idNum,iIndex]    
        try:
            resp = self.call("devices")
            if (self.debug): print resp
            if ('devices' in resp):
                self.oh.sendCommand('spotify_devices', json.dumps(resp))
   
                initOrder = 0
                partial = ""
                j = 0
                k = 1
                while(exitStatus == ""):
                    idx = 1
                    searchName = arrayDesc[(j%3)]
                    print "Match :", searchName , " or ", arrayDesc[((1 + j)%3)], "index: ", iIndex
                    intmed = str(searchName)
                    print intmed                   
                    print json.dumps(searchName)
                    for i in resp['devices']:
                        loopName = getJSONValue(i, ['name'])
                        
                        searchid = getJSONValue(i, ['id'])
                        print idx, "Device : " , loopName , "id :" ,searchid 
                        if (arrayDesc[(j%3)] ==  loopName) or (arrayDesc[((1 + j)%3)] == searchid) or (iIndex == idx ):
                            self.oh.sendCommand('spotify_device_name', loopName)
                            self.oh.sendCommand('spotify_device_id', searchid)
                            self.oh.sendCommand('spotify_device_index', idx)
                            exitStatus="Match Sucess"
                            selected_device = searchid
                            return selected_device
                        #Performs partial match serach if no results found
                        if (searchName): 
                            if searchName.lower() in loopName.lower():
                                partial =  searchid                              
                        idx = idx + 1
                    #Looks at the various inputs and seraches on each input in various fields                    
                    iIndex=""
                    j+=1
                    if( j > 3): exitStatus="FAILED"   
                    if (j == k):
                        k = 2
                        dev_desp=""
                        if (idNum): 
                            dev_desp = idNum
                            idNum=""
                            j  = 0
                            initOrder = 1
                            print "idNum serach" 
                        elif (devIndex) : 
                            dev_desp = devIndex
                            devIndex=""
                            j  = 0
                            iIndex=-1
                            initOrder = 2
                            print "devinx serach" 
                        elif (name) :
                            dev_desp = name
                            j  = 0
                            name = ""
                            initOrder = 0
                            print "name serach"                         
                        if (dev_desp):
                            smart_index = self.device_match(dev_desp)
                            if(smart_index > 0):
                                arrayDesc[smart_index] = dev_desp
                                if (smart_index == 2): 
                                    iIndex = int(dev_desp)
                                if (smart_index == initOrder): j = j + 1
                                
                        elif (partial):
                            k = 10
                            j = 3
                            arrayDesc[1] = partial
                            print "partial serach"

                print exitStatus
            else:
                print " -> Device list error :("
        except:
            print " -> Failure: ", sys.exc_info()[0]
            resp = ""
        return selected_device
    def removequotes(self,s): return "".join(i for i in s if i != "\"")
    def argsort(self, theargs = None):
        spotifyString="spotify:"
        myargs = ["",""]

        for i in range(2, len(theargs)):
            print theargs[i]
            stream=self.removequotes(theargs[i]).strip()            
            if spotifyString in theargs[i].lower():
                myargs[0] = myargs[0]  + stream + " "
            else: 
                myargs[1] = myargs[1] + stream + " "
        
        return self.removeEmpty(myargs)
    
  
    def removeEmpty(self, inString = None):
        print inString        
        for i in range(len(inString)):        
            if(inString[i] == ""):  inString[i] = None
            else: inString[i]=inString[i].strip()    
        return inString

    def sanitiseActions(self, uristring = None, device_string = None):
        new_device_id = self.devices(device_string)
        current_device = self.oh.getState('spotify_current_device_id')
        currently_playing = self.oh.getState('spotify_current_playing')
        ma=[uristring,device_string]
        if (current_device == new_device_id):
            ma[1]=""
        
        return ma

    
    def updateConnectionDateTime(self):
        self.oh.sendCommand('spotify_lastConnectionDateTime',time.strftime("%Y-%m-%dT%H:%M:%S.000+0000",time.gmtime(time.time())))   
        # self.oh.sendCommand('spotify_lastConnectionDateTime',time.strftime("%Y-%m-%dT%H:%M:%S+0000",time.gmtime(time.time())))     

def main():

    t1 = time.time()

    c = spotify()

    args = sys.argv
    
    if(len(args) == 1):
        c.update()
    else:

        if(args[1] == "volume_up"):
            c.volumeAdjust(10)
        if(args[1] == "volume_down"):
            c.volumeAdjust(-10)
        if(args[1] == "volume"):
            c.volume(args[2])
        if(args[1] == "mute"):
            c.volume("0")              
        if(args[1] == "play"):
            if(len(args)>2):
                ma = c.argsort(args)                                
                c.play(ma[0],c.devices(ma[1]))                
            else:
                c.play()
        if(args[1] == "playlists"):
            c.playlists()
        if(args[1] == "pause"):
            c.pause()
        if(args[1] == "previous"):
            c.previous()
        if(args[1] == "next"):
            c.next()
        if(args[1] == "shuffle"):
            c.shuffle()
        if(args[1] == "shuffleoff"):
            c.shuffleoff()
        if(args[1] == "devices"):
            if(len(args)>2):
                ma = c.argsort(args)  
                c.devices(ma[1])
            else:               
                c.devices()
        if(args[1] == "device_id"):
            if(len(args)>2):
                c.devices(None,args[2])
            else:
                c.devices()
        if(args[1] == "device_name"):
            if(len(args)>2):
                ma = c.argsort(args)  
                c.devices(ma[1])
            else:            
                c.devices()
        if(args[1] == "device_index"):
            if(len(args)>2):            
                c.devices(None, None, args[2])
            else:            
                c.devices()
        if(args[1] == "play_device"):
            ma = c.argsort(args)  
            c.play(ma[0], c.devices(ma[1]))
        if(args[1] == "play_device_name"):
            ma = c.argsort(args)  
            c.play(ma[0], c.devices(ma[1]))
                   
                              
    c.updateConnectionDateTime()

    t2 = time.time()
    print "Done in " + str(t2-t1) + " seconds"

if __name__ == '__main__':
    main()


(Spo0nerino) #167

HI guys

I already have the spotify web api running, but on every startup i lost the auth.

I saw in the configuration that you have to enable presistence but i dont know how to do that, can you help me please?

Best regards


(Joe Meier) #168

For MySQL see e.g. this tutorial, it did work out for me: openHAB2 & MySQL persistence setup


(Bram) #169

Same problem @OliM! Have you already found a solution?


(Alberto Forero) #170

Hello! Please I need help, following the tutorial I have a problem at the end, I copy the result below.
I do not know what to try

Blockquote

pi@Domotica:~ $ /usr/bin/python /etc/openhab2/scripts/spotify.py
Successfully got state from OpenHab: spotify_client_id
Successfully got state from OpenHab: spotify_client_secret
Successfully got state from OpenHab: spotify_access_token
Successfully got state from OpenHab: spotify_refresh_token
Successfully got state from OpenHab: spotify_token_issued
Successfully got state from OpenHab: spotify_token_expiry
– Calling Token Refresh Service
-> Error refreshing token:{u’error_description’: u’Invalid refresh token’, u’error’: u’invalid_grant’}
Successfully got state from OpenHab: spotify_auth_code
– Calling Token Service for the first time
Successfully posted state to OpenHab: spotify_access_token = XXXXXXXXXXXXXXXXXXXXGIE9oAsIPkvtNdrjL3km3i7B9g9x5kW379fAgC6PJOkmXe1PKYBFLjGIHQOqn8G02bjjCjhLj62aiQT7OWc5WMQxsH2w35H0-6dtvhDEpUNoSFd87FRLleFz9tY9thS0l5nA3QBTKlb9HH4
Successfully posted state to OpenHab: spotify_refresh_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXDt6cr-33Z9s0lXFR2sW4MO5pn6JCwegcSsacZV6VwH3DfUfH1g6Go3t3K8tS9nLqJZEpvdsPlqyYirIJjVfJsqHZX8K3YRw
Successfully posted state to OpenHab: spotify_token_expiry = 1516801970.35
Successfully posted state to OpenHab: spotify_token_issued = 2018-01-24T13:52:50
– Calling Service: Update

https://api.spotify.com/v1/me/player/
-> Failure: <class ‘simplejson.scanner.JSONDecodeError’>
Successfully posted state to OpenHab: spotify_lastConnectionDateTime = 2018-01-24T12:52:50.000+0000
Done in 1.43034410477 seconds

Where is the error?


(Tobias81) #171

Hi all!

If I click on the next song, I have to click on the update-button and then reload the page to see the new cover-image. Why?

Next song: ng-click="sendCmd(‘spotify_action’, ‘next’)"
Update: ng-click=“sendCmd(‘spotify_forceupadte’, ‘ON’)“
Cover-image: ng-style=”{‘background-image’: ‘url(’ + itemValue(‘spotify_current_cover’) + ‘)’}”

I got two rules:
Spotify-test:
rule “Spotify run script"
when
Time cron “0/1 * * * * ? *” or
Item spotify_forceupadte received update
then
val resp = executeCommandLine(”/usr/bin/python /etc/openhab2/scripts/spotify.py", 2000)
logInfo(“Spotify”, resp)
end

rule “Spotify Action"
when
Item spotify_action received update
then
val resp = executeCommandLine(”/usr/bin/python /etc/openhab2/scripts/spotify.py " + spotify_action.state.toString, 2000)
logInfo(“Spotify”, resp)
end

Spotify:
rule “Spotify run script"
when
Item spotify_forceupadte received update
then
val resp = executeCommandLine(”/usr/bin/python /etc/openhab2/scripts/spotify.py", 5000)
logInfo(“Spotify”, resp)
end

rule “Spotify Action"
when
Item spotify_action received update
then
val resp = executeCommandLine(”/usr/bin/python /etc/openhab2/scripts/spotify.py " + spotify_action.state.toString, 5000)
logInfo(“Spotify”, resp)
end


(Unparagoned) #172

Not sure. I get the image to load pretty much instantly when I press next or back. Maybe 10 seconds or so. No need to update status or refresh the page.

You have a time cron running every second all the time which might be a bit much for the spotify servers so they are limiting your connection which you only notice when you try and get an image. I have one that runs once every 30 seconds, but if spotify is playing then it will update every 5 seconds. I then used js as posted above to smooth the progress bar over those 5 sec.

Edit: I lied only update every 30 when spotify is active and once every half an hour otherwise, which is probably too conservative.

rule "spotify live update"
    when
        Time cron "0/30 * * * * ?"
    then

        if ( spotify_current_playing.state == ON && parse(spotify_lastConnectionDateTime.state.toString).plusSeconds(20).isBefore(now)){            
            sendCommand(spotify_forceupadte, ON)
            logInfo("Spotify", "Chrom live update run")	            
        }
end


	
rule "spotify update"
    when
        Time cron "0 0/30 * * * ?"
    then
        logInfo("Spotify", "Chron prelock")
        if (parse(spotify_lastConnectionDateTime.state.toString).plusSeconds(45).isBefore(now)){			

            sendCommand(spotify_forceupadte, ON)
            logInfo("Spotify", "Chrom  update run")	
        }
end

(Matt Dinsmore) #173

I have the same problem, I have set the Windows variables and can call python from the CMD line, but openHAB is still looking for its default path and resolving the variable;

Execution failed (Exit value: -559038737. Caused by java.io.IOException: Cannot run program "\usr\bin\python" (in directory ".")

Is there an option to change the biding or script to look for a Windows variables, or how can I get Windows to recognize that “\usr\bin\python” actually is C:\Python27. I am pretty sure that system variables cannot include "/"s


(Matt Dinsmore) #174

Whoops, this is clearly defined and can get set using true path in the spotify.rules file.

val resp =  executeCommandLine("C:\\Python27\\python.exe D:\\openHAB\\conf\\scripts\\spotify.py", 5000)

I must have been getting tunnel vision on the actual scripts themselves - Cheers


(Sasha) #175

Hi All,

It’s all working fine, thanks for the work!!

Except when I update the items file or reboot openhab I have to manually assign id and secret and then authenticate on spotify-auth.html.
Any solution for this, or am I missing something?

Thanks!

PS. Persistence is recording any change:

Strategies {
	everyMinute : "0 * * * * ?"
	everyHour 	: "0 0 * * * ?"
	everyDay	: "0 0 0 * * ?"
	default = everyChange
}

Items {
	// persist everything when the value is updated, just a default, and restore them from database on startup
	* : strategy = everyChange, everyMinute, restoreOnStartup
}

(Markus Schulte) #176

I´ve got always :

Successfully got state from OpenHab: spotify_client_id
Successfully got state from OpenHab: spotify_client_secret
Successfully got state from OpenHab: spotify_access_token
Successfully got state from OpenHab: spotify_refresh_token
Successfully got state from OpenHab: spotify_token_issued
Successfully got state from OpenHab: spotify_token_expiry
-- Calling Service: Update
 -> Failure:  <type 'exceptions.ValueError'>

Is the redirect URI REDIRECT_URI = ‘http://openhabianpi.local:8080/static/spotify-auth.html’ correct in spotify.py ???

Thanks for help

Mad

Edit : Got it


(Oneofayykind) #178

I’m running this on a mac so I changed the redirect URI to http://localhost:8080/static/spotify-auth.html

Samanthas-iMac:scripts SamanthaAllen$ python spotify.py
Successfully got state from OpenHab: spotify_client_id
Successfully got state from OpenHab: spotify_client_secret
Successfully got state from OpenHab: spotify_access_token
Successfully got state from OpenHab: spotify_refresh_token
Successfully got state from OpenHab: spotify_token_issued
Successfully got state from OpenHab: spotify_token_expiry
– Calling Service: Update
-> Failure: <type ‘exceptions.ValueError’>
Error posting state to OpenHab: spotify_lastConnectionDateTime (HTTP Response State could not be parsed: 2018-02-20T16:33:17+0000)
Done in 1.39271020889 seconds


(Markus Schulte) #179

This helps :

openHAB integration to Spotify Web Connect API (player)


(Oneofayykind) #180

Thanks. I’m at the point where I need to configure a persistence db and when I try installing mysql in terminal for mac it asks for a password. I have no clue what this password could possibly be. It’s not my mac password and the habopen default password I read about is not working. Any ideas?


(Mike) #181

It took me a while to figure out that you have to set it in spotify.py, and also set it in the app settings in the Spotify developer dashboard. I don’t see that 2nd step identified anywhere here.


(Mike) #182

So I am having trouble with persistence. I have to re-auth every time Openhab restarts. Where can I put the values for spotify_client_id and spotify_client_secret so that they can be loaded when Openhab starts?


(Sasha) #183

I’ve got some items updated on the startup, I’ve included Spotify id’s but I still have to re-authenticate…
Would love it to be a permanent thing

rule "Initialize items on startup"
when
    System started
then
    postUpdate(spotify_client_id, "99852********************923d5b")
    postUpdate(spotify_client_secret, "c5a47bf********************69c039")
end

(Unparagoned) #184

I don’t know why soo many people are having problems with persistence. It should work fine with any persistent setup. Here is my setup for reference.

Install MapDB persistence in PaperUI. Under settings set Persistence as MapDB. Then set mapdb.persist to

Strategies {
		everyHour : "0 0 * * * ?"
    	everyDay  : "0 0 0 * * ?"
		default = everyUpdate
}

Items {
		* : strategy = everyChange, everyDay, restoreOnStartup
}

That should make sure all the key items are restored on restart. Note the client id and secret are for the initial authorisation. Its the auth token, etc that need to be persisted so you don’t have to manually re- auth each time.

/* Strings for Primary Auth */
String spotify_auth_code (sgstring)
String spotify_client_id (sgstring)
String spotify_client_secret (sgstring)

/* Strings for Token Auth */
String spotify_auth "http://debra.local:8080/static/spotify-auth.html" //This is likely a temp junk item I added that you don't need
String spotify_access_token "AccessToken [%s]" (sgstring)
String spotify_refresh_token "RefreshToken [%s]" (sgstring)
String spotify_token_expiry "TokenExpiry [%s]" (sgstring)
DateTime spotify_token_issued "TokenIssued [%s]"

Oh @mbibbey the readme is very clear with bullet points for all the steps. https://github.com/pmpkk/openhab_spotify-webconnect-api

* After registering as a Spotify developer, create a new App and retrieve client id and secret:
* Goto https://developer.spotify.com/my-applications/#!/applications
* Click "Create App"
* Provide a name and description
* **Set the Redirect URI to: http://openhabianpi.local:8080/static/spotify-auth.html**
* Save the Settings