Closed eawystr closed 3 years ago
I have been reviewing everything a lot of times, but still the same error:
Connected to haifisch IP address: 192.168.1.137 Refreshing Access Tokens grant_type=refresh_token&refresh_token=xxxxxxxxxxxxxxxxx&client_id=xxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxx stack size -1073421775 accounts.spotify.com Status Code: 200 status Code200 Closing client Free Heap: 277872 getting currently playing song: /v1/me/player/currently-playing?market=ES stack size -1073421711 Status Code: -1 stack size -1073421711 Closing client Free Heap: 278348 getting currently playing song: /v1/me/player/currently-playing?market=ES stack size -1073421711 Status Code: -1 stack size -1073421711 Closing client
And so on.
Any clues?
Can you try test the callbacks branch?
https://github.com/witnessmenow/spotify-api-arduino/tree/Callbacks
That is the latest code and it would be easier for me to debug that rather than going back to old code that will be replaced by the callbacks branch shortly anyways.
The callbacks branch brings a fairly significant change in the way the library is called, but the getCurrentlyPlaying example should just work if you update your secret refresh token etc
Testesd.
The getRefreshToken example worked, but when trying the getCurrentlyPlaying it brings this error and it keeps rebooting:
.....
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=xxxxxx&client_id=xxxxxx&client_secret=xxxxxxx
stack size -1073421775
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x81000000 PS : 0x00060c30 A0 : 0x800d4600 A1 : 0x3ffb1dd0
A2 : 0x3ffc1764 A3 : 0x3f400ded A4 : 0x000000a0 A5 : 0x78f383b8
A6 : 0x3ffb1cd0 A7 : 0x3f400d92 A8 : 0x800d2fad A9 : 0x3ffb1db0
A10 : 0x3ffc1864 A11 : 0x40086860 A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000014
EXCVADDR: 0x81000000 LBEG : 0x400012c5 LEND : 0x400012d5 LCOUNT : 0xfffffff4
ELF file SHA256: 0000000000000000
Backtrace: 0x41000000:0x3ffb1dd0 0x400d45fd:0x3ffb1df0 0x400d0b32:0x3ffb1f70 0x400d57f6:0x3ffb1fb0 0x400897b2:0x3ffb1fd0
Rebooting...
Just tested that example there now and its working fine.
Can you link to the song you are listening to maybe?
It would also be useful to see what that stack trace says: https://github.com/me-no-dev/EspExceptionDecoder
Also, do you have spotify premium?
Yes, I have premium and it happens with all songs.
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=xxxxx&client_id=xxxxx&client_secret=xxxx
stack size -1073421775
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x00000000 PS : 0x00060c30 A0 : 0x800d4600 A1 : 0x3ffb1dd0
A2 : 0x3ffc1764 A3 : 0x3f400ded A4 : 0x000000a0 A5 : 0x410d337d
A6 : 0x3ffb1cd0 A7 : 0x3f400d92 A8 : 0x800d2fad A9 : 0x3ffb1db0
A10 : 0x3ffc1864 A11 : 0x40086860 A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000014
EXCVADDR: 0x00000000 LBEG : 0x400012c5 LEND : 0x400012d5 LCOUNT : 0xfffffff4
ELF file SHA256: 0000000000000000
Backtrace: 0x00000000:0x3ffb1dd0 0x400d45fd:0x3ffb1df0 0x400d0b32:0x3ffb1f70 0x400d57f6:0x3ffb1fb0 0x400897b2:0x3ffb1fd0
PC: 0x00000000 EXCVADDR: 0x00000000
Decoding stack results 0x400d45fd: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-Callbacks\src\SpotifyArduino.cpp line 202 0x400d0b32: setup() at C:\Users\David Calderon\Documents\Arduino\Spotify API\getCurrentlyPlaying/getCurrentlyPlaying.ino line 115 0x400d57f6: loopTask(void*) at C:\Users\David Calderon\AppData\Local\arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\main.cpp line 18 0x400897b2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Very strange. It seems to be crashing somewhere when you refresh your access token, but the call has a status 200.
Can you please update the code again from the callback branch, I've added some extra debugging on that method.
After you update could please enable #define SPOTIFY_PRINT_JSON_PARSE 1
in SpotifyArduino.h and install https://github.com/bblanchon/ArduinoStreamUtils
Same...
....
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=xxxxxx&client_id=xxxxxa&client_secret=xxxxxx
stack size -1073421775
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x00000000 PS : 0x00060c30 A0 : 0x800d461a A1 : 0x3ffb1dd0
A2 : 0x3ffc1764 A3 : 0x3f400ded A4 : 0x000000a0 A5 : 0xc6908d22
A6 : 0x3ffb1cd0 A7 : 0x3f400d92 A8 : 0x800d2fad A9 : 0x3ffb1db0
A10 : 0x3ffc1864 A11 : 0x40086860 A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000014
EXCVADDR: 0x00000000 LBEG : 0x400012c5 LEND : 0x400012d5 LCOUNT : 0xfffffff4
ELF file SHA256: 0000000000000000
Backtrace: 0x00000000:0x3ffb1dd0 0x400d4617:0x3ffb1df0 0x400d0b32:0x3ffb1f70 0x400d5816:0x3ffb1fb0 0x400897b2:0x3ffb1fd0
PC: 0x00000000 EXCVADDR: 0x00000000
Decoding stack results 0x400d4617: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-Callbacks\src\SpotifyArduino.cpp line 216 0x400d0b32: setup() at C:\Users\DAVIDC~1\AppData\Local\Temp\arduino_modified_sketch_956359/getCurrentlyPlaying.ino line 114 0x400d5816: loopTask(void*) at C:\Users\David Calderon\AppData\Local\arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\main.cpp line 18 0x400897b2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Can you confirm your enabled the SPOTIFY_PRINT_JSON_PARSE flag?
Can you take a screen shot of your board settings in the Arduino ide?
Yes, I've enabled it. Im working on a AZ-DELIVERY ESP32 WROOM 32
Hi,
Any clues?
I am getting mad on this...
Get mad all you like. Works for me Figure it out yourself
Sorry, I didn’t wanted to bother you
You clearly did though.... 😂
I think there was a misunderstanding in what was said, @eawystr apologised so I am re-opening
@eawystr , I think a few places to start:
Serial.println("1")
(change the number so you can tell which one) to the code in the library to see where it's getting. I can tell from your logs that it's getting to here: https://github.com/witnessmenow/spotify-api-arduino/blob/Callbacks/src/SpotifyArduino.cpp#L183, but the crash happens after that without any other printsTo modify the library, edit this file: C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-Callbacks\src\SpotifyArduino.cpp
Can you also post the code of the refreshAccessToken
function after you have edited it.
Hi again @witnessmenow and thanks for reopen the issue.
The ESP32 that I am using is a brand new (AZDelivery WROOM32), it works fine with other program, but I have bought a new ESP32 (the one that you recommend on the library) because is the only one that I have.
I've been adding Serial.println("1")
with a different number on different lines on SpotifyArduino.cpp and it goes until lines 214, 215, 216 ultil return refreshed;
If I add the Serial.println("1")
after that line, it doesn't appear. If added it in other parts of the library, it doesn't appear.
And, this is the code that works for me (is the getRefreshToken example literally changing the soptify parameters and adding user-read-currently-playing scope):
(Thanks for your time and patience)
/*******************************************************************
Get Refresh Token from spotify, this is needed for the other
examples.
Instructions:
- Put in your Wifi details, Client ID, Client secret and flash to the board
- Do one of the following
--- IF USING IP (ESP32 MDNS does not work for me)
- Get the Ip Address from the serial monitor
- Add the following to Redirect URI on your Spotify app "http://[ESP_IP]/callback/"
e.g. "http://192.168.1.20/callback/" (don't forget the last "/")
- Open browser to esp using the IP
--- IF USING MDNS
- Search for "#define USE_IP_ADDRESS" and comment it out
- Add the following to Redirect URI on your Spotify app "http://arduino.local/callback/"
(don't forget the last "/")
- Open browser to esp: http://arduino.local
-----------
- Click the link on the webpage
- The Refresh Token will be printed to screen, use this
for SPOTIFY_REFRESH_TOKEN in other examples.
Compatible Boards:
- Any ESP8266 or ESP32 board
Parts:
ESP32 D1 Mini style Dev board* - http://s.click.aliexpress.com/e/C6ds4my
* * = Affiliate
If you find what I do useful and would like to support me,
please consider becoming a sponsor on Github
https://github.com/sponsors/witnessmenow/
Written by Brian Lough
YouTube: https://www.youtube.com/brianlough
Tindie: https://www.tindie.com/stores/brianlough/
Twitter: https://twitter.com/witnessmenow
*******************************************************************/
// ----------------------------
// Standard Libraries
// ----------------------------
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#endif
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
// ----------------------------
// Additional Libraries - each one of these will need to be installed.
// ----------------------------
#include <SpotifyArduino.h>
// Library for connecting to the Spotify API
// Install from Github
// https://github.com/witnessmenow/spotify-api-arduino
// including a "spotify_server_cert" variable
// header is included as part of the SpotifyArduino libary
#include <SpotifyArduinoCert.h>
#include <ArduinoJson.h>
// Library used for parsing Json from the API responses
// Search for "Arduino Json" in the Arduino Library manager
// https://github.com/bblanchon/ArduinoJson
//------- Replace the following! ------
char ssid[] = "haifisch"; // your network SSID (name)
char password[] = "xxxxxxxx"; // your network password
char clientId[] = "xxxxxxxxxxxxxxxxxxx"; // Your client ID of your spotify APP
char clientSecret[] = "xxxxxxxxxxxxxxx"; // Your client Secret of your spotify APP (Do Not share this!)
char scope[] = "user-read-playback-state%20user-read-currently-playing";
#define USE_IP_ADDRESS 1 //comment this out if you want to use MDNS
#ifdef USE_IP_ADDRESS
char callbackURItemplate[] = "%s%s%s";
char callbackURIProtocol[] = "http%3A%2F%2F"; // "http://"
char callbackURIAddress[] = "%2Fcallback%2F"; // "/callback/"
char callbackURI[100];
#else
char callbackURI[] = "http%3A%2F%2Farduino.local%2Fcallback%2F";
#endif
//------- ---------------------- ------
#if defined(ESP8266)
ESP8266WebServer server(80);
#elif defined(ESP32)
WebServer server(80);
#endif
WiFiClientSecure client;
SpotifyArduino spotify(client, clientId, clientSecret);
const char *webpageTemplate =
R"(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
</head>
<body>
<div>
<a href="https://accounts.spotify.com/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=%s">spotify Auth</a>
</div>
</body>
</html>
)";
void handleRoot()
{
char webpage[800];
sprintf(webpage, webpageTemplate, clientId, callbackURI, scope);
server.send(200, "text/html", webpage);
}
void handleCallback()
{
String code = "";
const char *refreshToken = NULL;
for (uint8_t i = 0; i < server.args(); i++)
{
if (server.argName(i) == "code")
{
code = server.arg(i);
refreshToken = spotify.requestAccessTokens(code.c_str(), callbackURI);
}
}
if (refreshToken != NULL)
{
server.send(200, "text/plain", refreshToken);
}
else
{
server.send(404, "text/plain", "Failed to load token, check serial monitor");
}
}
void handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++)
{
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
Serial.print(message);
server.send(404, "text/plain", message);
}
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
IPAddress ipAddress = WiFi.localIP();
Serial.println(ipAddress);
if (MDNS.begin("arduino"))
{
Serial.println("MDNS responder started");
}
// Handle HTTPS Verification
#if defined(ESP8266)
client.setFingerprint(SPOTIFY_FINGERPRINT); // These expire every few months
#elif defined(ESP32)
client.setCACert(spotify_server_cert);
#endif
// ... or don't!
//client.setInsecure();
// If you want to enable some extra debugging
// uncomment the "#define SPOTIFY_DEBUG" in ArduinoSpotify.h
#ifdef USE_IP_ADDRESS
// Building up callback URL using IP address.
sprintf(callbackURI, callbackURItemplate, callbackURIProtocol, ipAddress.toString().c_str(), callbackURIAddress);
#endif
server.on("/", handleRoot);
server.on("/callback/", handleCallback);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop()
{
#if defined(ESP8266)
MDNS.update();
#endif
server.handleClient();
}
Can you paste your serial output and refresh access token method after your serial prints?
Done.
.....
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=AQBQ4P7YXiklMZ9oyGA4JOXQB9Y-cKvbqtNzJuQRk6quLheFl5rtY77a34RAGz9oLGuSYb_4dYYTD1e74JUICqBRe6oycc7FEwfE_1KcL5CWOGKR8OjPs_yZaW_j9zaYWik&client_id=f8aeea367669458dac14b17261ff61ea&client_secret=19cacb238db34764913ab16b7a210b98
stack size -1073421775
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
1
2
3
Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x00000000 PS : 0x00060c30 A0 : 0x800d4669 A1 : 0x3ffb1dd0
A2 : 0x3ffc1764 A3 : 0x00000001 A4 : 0x000000a0 A5 : 0xc787efc4
A6 : 0x3ffb1cd0 A7 : 0x3f400d92 A8 : 0x800d2fcd A9 : 0x3ffb1db0
A10 : 0x3ffc1864 A11 : 0x3f400e1e A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000014
EXCVADDR: 0x00000000 LBEG : 0x400012c5 LEND : 0x400012d5 LCOUNT : 0xfffffff4
ELF file SHA256: 0000000000000000
Backtrace: 0x00000000:0x3ffb1dd0 0x400d4666:0x3ffb1df0 0x400d0b52:0x3ffb1f70 0x400d58a6:0x3ffb1fb0 0x400897b2:0x3ffb1fd0
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1216
ho 0 tail 12 room 4
load:0x40078000,len:10944
load:0x40080400,len:6388
entry 0x400806b4
And decoded:
PC: 0x00000000
EXCVADDR: 0x00000000
Decoding stack results
0x400d4666: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-Callbacks\src\SpotifyArduino.cpp line 216
0x400d0b52: setup() at C:\Users\David Calderon\Documents\Arduino\sketch_aug19b/sketch_aug19b.ino line 114
0x400d58a6: loopTask(void*) at C:\Users\David Calderon\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\main.cpp line 18
0x400897b2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
And the modified SpotifyArduino.cpp:
/*
SpotifyArduino - An Arduino library to wrap the Spotify API
Copyright (c) 2021 Brian Lough.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "SpotifyArduino.h"
SpotifyArduino::SpotifyArduino(Client &client, char *bearerToken)
{
this->client = &client;
sprintf(this->_bearerToken, "Bearer %s", bearerToken);
}
SpotifyArduino::SpotifyArduino(Client &client, const char *clientId, const char *clientSecret, const char *refreshToken)
{
this->client = &client;
this->_clientId = clientId;
this->_clientSecret = clientSecret;
this->_refreshToken = refreshToken;
}
int SpotifyArduino::makeRequestWithBody(const char *type, const char *command, const char *authorization, const char *body, const char *contentType, const char *host)
{
client->flush();
#ifdef SPOTIFY_DEBUG
Serial.println(host);
#endif
client->setTimeout(SPOTIFY_TIMEOUT);
if (!client->connect(host, portNumber))
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println(F("Connection failed"));
#endif
return -1;
}
// give the esp a breather
yield();
// Send HTTP request
client->print(type);
client->print(command);
client->println(F(" HTTP/1.0"));
//Headers
client->print(F("Host: "));
client->println(host);
client->println(F("Accept: application/json"));
client->print(F("Content-Type: "));
client->println(contentType);
if (authorization != NULL)
{
client->print(F("Authorization: "));
client->println(authorization);
}
client->println(F("Cache-Control: no-cache"));
client->print(F("Content-Length: "));
client->println(strlen(body));
client->println();
client->print(body);
if (client->println() == 0)
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println(F("Failed to send request"));
#endif
return -2;
}
int statusCode = getHttpStatusCode();
return statusCode;
}
int SpotifyArduino::makePutRequest(const char *command, const char *authorization, const char *body, const char *contentType, const char *host)
{
return makeRequestWithBody("PUT ", command, authorization, body, contentType);
}
int SpotifyArduino::makePostRequest(const char *command, const char *authorization, const char *body, const char *contentType, const char *host)
{
return makeRequestWithBody("POST ", command, authorization, body, contentType, host);
}
int SpotifyArduino::makeGetRequest(const char *command, const char *authorization, const char *accept, const char *host)
{
client->flush();
client->setTimeout(SPOTIFY_TIMEOUT);
if (!client->connect(host, portNumber))
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println(F("Connection failed"));
#endif
return -1;
}
// give the esp a breather
yield();
// Send HTTP request
client->print(F("GET "));
client->print(command);
client->println(F(" HTTP/1.0"));
//Headers
client->print(F("Host: "));
client->println(host);
if (accept != NULL)
{
client->print(F("Accept: "));
client->println(accept);
}
if (authorization != NULL)
{
client->print(F("Authorization: "));
client->println(authorization);
}
client->println(F("Cache-Control: no-cache"));
if (client->println() == 0)
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println(F("Failed to send request"));
#endif
return -2;
}
int statusCode = getHttpStatusCode();
return statusCode;
}
void SpotifyArduino::setRefreshToken(const char *refreshToken)
{
_refreshToken = refreshToken;
}
bool SpotifyArduino::refreshAccessToken()
{
char body[300];
sprintf(body, refreshAccessTokensBody, _refreshToken, _clientId, _clientSecret);
#ifdef SPOTIFY_DEBUG
Serial.println(body);
printStack();
#endif
int statusCode = makePostRequest(SPOTIFY_TOKEN_ENDPOINT, NULL, body, "application/x-www-form-urlencoded", SPOTIFY_ACCOUNTS_HOST);
if (statusCode > 0)
{
skipHeaders();
}
unsigned long now = millis();
#ifdef SPOTIFY_DEBUG
Serial.print("status Code");
Serial.println(statusCode);
#endif
Serial.println("1");
bool refreshed = false;
if (statusCode == 200)
{
DynamicJsonDocument doc(1000);
Serial.println("2");
// Parse JSON object
#ifndef SPOTIFY_PRINT_JSON_PARSE
DeserializationError error = deserializeJson(doc, *client);
#else
ReadLoggingStream loggingStream(*client, Serial);
DeserializationError error = deserializeJson(doc, loggingStream);
#endif
if (!error)
{
sprintf(this->_bearerToken, "Bearer %s", doc["access_token"].as<const char *>());
int tokenTtl = doc["expires_in"]; // Usually 3600 (1 hour)
tokenTimeToLiveMs = (tokenTtl * 1000) - 2000; // The 2000 is just to force the token expiry to check if its very close
timeTokenRefreshed = now;
refreshed = true;
}
else
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
#endif
}
}
else
{
parseError();
}
Serial.println("3");
closeClient();
Serial.println("4");
return refreshed;
Serial.println("5");
}
bool SpotifyArduino::checkAndRefreshAccessToken()
{
Serial.println("6");
unsigned long timeSinceLastRefresh = millis() - timeTokenRefreshed;
Serial.println("7");
if (timeSinceLastRefresh >= tokenTimeToLiveMs)
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println("Refresh of the Access token is due, doing that now.");
#endif
Serial.println("8");
return refreshAccessToken();
}
// Token is still valid
Serial.println("9");
return true;
}
const char *SpotifyArduino::requestAccessTokens(const char *code, const char *redirectUrl)
{
char body[500];
sprintf(body, requestAccessTokensBody, code, redirectUrl, _clientId, _clientSecret);
#ifdef SPOTIFY_DEBUG
Serial.println(body);
#endif
int statusCode = makePostRequest(SPOTIFY_TOKEN_ENDPOINT, NULL, body, "application/x-www-form-urlencoded", SPOTIFY_ACCOUNTS_HOST);
if (statusCode > 0)
{
skipHeaders();
}
unsigned long now = millis();
#ifdef SPOTIFY_DEBUG
Serial.print("status Code");
Serial.println(statusCode);
#endif
if (statusCode == 200)
{
DynamicJsonDocument doc(1000);
// Parse JSON object
#ifndef SPOTIFY_PRINT_JSON_PARSE
DeserializationError error = deserializeJson(doc, *client);
#else
ReadLoggingStream loggingStream(*client, Serial);
DeserializationError error = deserializeJson(doc, loggingStream);
#endif
if (!error)
{
sprintf(this->_bearerToken, "Bearer %s", doc["access_token"].as<const char *>());
_refreshToken = doc["refresh_token"].as<const char *>();
int tokenTtl = doc["expires_in"]; // Usually 3600 (1 hour)
tokenTimeToLiveMs = (tokenTtl * 1000) - 2000; // The 2000 is just to force the token expiry to check if its very close
timeTokenRefreshed = now;
}
else
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
#endif
}
}
else
{
parseError();
}
closeClient();
return _refreshToken;
}
bool SpotifyArduino::play(const char *deviceId)
{
char command[100] = SPOTIFY_PLAY_ENDPOINT;
return playerControl(command, deviceId);
}
bool SpotifyArduino::playAdvanced(char *body, const char *deviceId)
{
char command[100] = SPOTIFY_PLAY_ENDPOINT;
return playerControl(command, deviceId, body);
}
bool SpotifyArduino::pause(const char *deviceId)
{
char command[100] = SPOTIFY_PAUSE_ENDPOINT;
return playerControl(command, deviceId);
}
bool SpotifyArduino::setVolume(int volume, const char *deviceId)
{
char command[125];
sprintf(command, SPOTIFY_VOLUME_ENDPOINT, volume);
return playerControl(command, deviceId);
}
bool SpotifyArduino::toggleShuffle(bool shuffle, const char *deviceId)
{
char command[125];
char shuffleState[10];
if (shuffle)
{
strcpy(shuffleState, "true");
}
else
{
strcpy(shuffleState, "false");
}
sprintf(command, SPOTIFY_SHUFFLE_ENDPOINT, shuffleState);
return playerControl(command, deviceId);
}
bool SpotifyArduino::setRepeatMode(RepeatOptions repeat, const char *deviceId)
{
char command[125];
char repeatState[10];
switch (repeat)
{
case repeat_track:
strcpy(repeatState, "track");
break;
case repeat_context:
strcpy(repeatState, "context");
break;
case repeat_off:
strcpy(repeatState, "off");
break;
}
sprintf(command, SPOTIFY_REPEAT_ENDPOINT, repeatState);
return playerControl(command, deviceId);
}
bool SpotifyArduino::playerControl(char *command, const char *deviceId, const char *body)
{
if (deviceId[0] != 0)
{
char *questionMarkPointer;
questionMarkPointer = strchr(command, '?');
char deviceIdBuff[50];
if (questionMarkPointer == NULL)
{
sprintf(deviceIdBuff, "?device_id=%s", deviceId);
}
else
{
// params already started
sprintf(deviceIdBuff, "&device_id=%s", deviceId);
}
strcat(command, deviceIdBuff);
}
#ifdef SPOTIFY_DEBUG
Serial.println(command);
Serial.println(body);
#endif
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makePutRequest(command, _bearerToken, body);
closeClient();
//Will return 204 if all went well.
return statusCode == 204;
}
bool SpotifyArduino::playerNavigate(char *command, const char *deviceId)
{
if (deviceId[0] != 0)
{
char deviceIdBuff[50];
sprintf(deviceIdBuff, "?device_id=%s", deviceId);
strcat(command, deviceIdBuff);
}
#ifdef SPOTIFY_DEBUG
Serial.println(command);
#endif
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makePostRequest(command, _bearerToken);
closeClient();
//Will return 204 if all went well.
return statusCode == 204;
}
bool SpotifyArduino::nextTrack(const char *deviceId)
{
char command[100] = SPOTIFY_NEXT_TRACK_ENDPOINT;
return playerNavigate(command, deviceId);
}
bool SpotifyArduino::previousTrack(const char *deviceId)
{
char command[100] = SPOTIFY_PREVIOUS_TRACK_ENDPOINT;
return playerNavigate(command, deviceId);
}
bool SpotifyArduino::seek(int position, const char *deviceId)
{
char command[100] = SPOTIFY_SEEK_ENDPOINT;
char tempBuff[100];
sprintf(tempBuff, "?position_ms=%d", position);
strcat(command, tempBuff);
if (deviceId[0] != 0)
{
sprintf(tempBuff, "?device_id=%s", deviceId);
strcat(command, tempBuff);
}
#ifdef SPOTIFY_DEBUG
Serial.println(command);
printStack();
#endif
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makePutRequest(command, _bearerToken);
closeClient();
//Will return 204 if all went well.
return statusCode == 204;
}
bool SpotifyArduino::transferPlayback(const char *deviceId, bool play)
{
char body[100];
sprintf(body, "{\"device_ids\":[\"%s\"],\"play\":\"%s\"}", deviceId, (play ? "true" : "false"));
#ifdef SPOTIFY_DEBUG
Serial.println(SPOTIFY_PLAYER_ENDPOINT);
Serial.println(body);
printStack();
#endif
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makePutRequest(SPOTIFY_PLAYER_ENDPOINT, _bearerToken, body);
closeClient();
//Will return 204 if all went well.
return statusCode == 204;
}
int SpotifyArduino::getCurrentlyPlaying(processCurrentlyPlaying currentlyPlayingCallback, const char *market)
{
Serial.println("3");
char command[50] = SPOTIFY_CURRENTLY_PLAYING_ENDPOINT;
if (market[0] != 0)
{
char marketBuff[15];
sprintf(marketBuff, "?market=%s", market);
strcat(command, marketBuff);
}
#ifdef SPOTIFY_DEBUG
Serial.println(command);
printStack();
#endif
// Get from https://arduinojson.org/v6/assistant/
const size_t bufferSize = currentlyPlayingBufferSize;
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makeGetRequest(command, _bearerToken);
#ifdef SPOTIFY_DEBUG
Serial.print("Status Code: ");
Serial.println(statusCode);
printStack();
#endif
if (statusCode > 0)
{
skipHeaders();
}
if (statusCode == 200)
{
CurrentlyPlaying current;
//Apply Json Filter: https://arduinojson.org/v6/example/filter/
StaticJsonDocument<288> filter;
filter["is_playing"] = true;
filter["progress_ms"] = true;
JsonObject filter_item = filter.createNestedObject("item");
filter_item["duration_ms"] = true;
filter_item["name"] = true;
filter_item["uri"] = true;
JsonObject filter_item_artists_0 = filter_item["artists"].createNestedObject();
filter_item_artists_0["name"] = true;
filter_item_artists_0["uri"] = true;
JsonObject filter_item_album = filter_item.createNestedObject("album");
filter_item_album["name"] = true;
filter_item_album["uri"] = true;
JsonObject filter_item_album_images_0 = filter_item_album["images"].createNestedObject();
filter_item_album_images_0["height"] = true;
filter_item_album_images_0["width"] = true;
filter_item_album_images_0["url"] = true;
// Allocate DynamicJsonDocument
DynamicJsonDocument doc(bufferSize);
// Parse JSON object
#ifndef SPOTIFY_PRINT_JSON_PARSE
DeserializationError error = deserializeJson(doc, *client, DeserializationOption::Filter(filter));
#else
ReadLoggingStream loggingStream(*client, Serial);
DeserializationError error = deserializeJson(doc, loggingStream, DeserializationOption::Filter(filter));
#endif
if (!error)
{
#ifdef SPOTIFY_DEBUG
serializeJsonPretty(doc, Serial);
#endif
JsonObject item = doc["item"];
int numArtists = item["artists"].size();
if (numArtists > SPOTIFY_MAX_NUM_ARTISTS)
{
numArtists = SPOTIFY_MAX_NUM_ARTISTS;
}
current.numArtists = numArtists;
for (int i = 0; i < current.numArtists; i++)
{
current.artists[i].artistName = item["artists"][i]["name"].as<const char *>();
current.artists[i].artistUri = item["artists"][i]["uri"].as<const char *>();
}
current.albumName = item["album"]["name"].as<const char *>();
current.albumUri = item["album"]["uri"].as<const char *>();
JsonArray images = item["album"]["images"];
// Images are returned in order of width, so last should be smallest.
int numImages = images.size();
int startingIndex = 0;
if (numImages > SPOTIFY_NUM_ALBUM_IMAGES)
{
startingIndex = numImages - SPOTIFY_NUM_ALBUM_IMAGES;
current.numImages = SPOTIFY_NUM_ALBUM_IMAGES;
}
else
{
current.numImages = numImages;
}
#ifdef SPOTIFY_DEBUG
Serial.print(F("Num Images: "));
Serial.println(current.numImages);
Serial.println(numImages);
#endif
for (int i = 0; i < current.numImages; i++)
{
int adjustedIndex = startingIndex + i;
current.albumImages[i].height = images[adjustedIndex]["height"].as<int>();
current.albumImages[i].width = images[adjustedIndex]["width"].as<int>();
current.albumImages[i].url = images[adjustedIndex]["url"].as<const char *>();
}
current.trackName = item["name"].as<const char *>();
current.trackUri = item["uri"].as<const char *>();
current.isPlaying = doc["is_playing"].as<bool>();
current.progressMs = doc["progress_ms"].as<long>();
current.durationMs = item["duration_ms"].as<long>();
currentlyPlayingCallback(current);
}
else
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
#endif
statusCode = -1;
}
}
closeClient();
return statusCode;
}
int SpotifyArduino::getPlayerDetails(processPlayerDetails playerDetailsCallback, const char *market)
{
char command[100] = SPOTIFY_PLAYER_ENDPOINT;
if (market[0] != 0)
{
char marketBuff[30];
sprintf(marketBuff, "?market=%s", market);
strcat(command, marketBuff);
}
#ifdef SPOTIFY_DEBUG
Serial.println(command);
printStack();
#endif
// Get from https://arduinojson.org/v6/assistant/
const size_t bufferSize = playerDetailsBufferSize;
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makeGetRequest(command, _bearerToken);
#ifdef SPOTIFY_DEBUG
Serial.print("Status Code: ");
Serial.println(statusCode);
#endif
if (statusCode > 0)
{
skipHeaders();
}
if (statusCode == 200)
{
StaticJsonDocument<192> filter;
JsonObject filter_device = filter.createNestedObject("device");
filter_device["id"] = true;
filter_device["name"] = true;
filter_device["type"] = true;
filter_device["is_active"] = true;
filter_device["is_private_session"] = true;
filter_device["is_restricted"] = true;
filter_device["volume_percent"] = true;
filter["progress_ms"] = true;
filter["is_playing"] = true;
filter["shuffle_state"] = true;
filter["repeat_state"] = true;
// Allocate DynamicJsonDocument
DynamicJsonDocument doc(bufferSize);
// Parse JSON object
#ifndef SPOTIFY_PRINT_JSON_PARSE
DeserializationError error = deserializeJson(doc, *client, DeserializationOption::Filter(filter));
#else
ReadLoggingStream loggingStream(*client, Serial);
DeserializationError error = deserializeJson(doc, loggingStream, DeserializationOption::Filter(filter));
#endif
if (!error)
{
PlayerDetails playerDetails;
JsonObject device = doc["device"];
// Copy into buffer and make the last character a null just incase we went over.
playerDetails.device.id = device["id"].as<const char *>();
playerDetails.device.name = device["name"].as<const char *>();
playerDetails.device.type = device["type"].as<const char *>();
playerDetails.device.isActive = device["is_active"].as<bool>();
playerDetails.device.isPrivateSession = device["is_private_session"].as<bool>();
playerDetails.device.isRestricted = device["is_restricted"].as<bool>();
playerDetails.device.volumePercent = device["volume_percent"].as<int>();
playerDetails.progressMs = doc["progress_ms"].as<long>();
playerDetails.isPlaying = doc["is_playing"].as<bool>();
playerDetails.shuffleState = doc["shuffle_state"].as<bool>();
const char *repeat_state = doc["repeat_state"];
if (strncmp(repeat_state, "track", 5) == 0)
{
playerDetails.repeateState = repeat_track;
}
else if (strncmp(repeat_state, "context", 7) == 0)
{
playerDetails.repeateState = repeat_context;
}
else
{
playerDetails.repeateState = repeat_off;
}
playerDetailsCallback(playerDetails);
}
else
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
#endif
statusCode = -1;
}
}
closeClient();
return statusCode;
}
int SpotifyArduino::getDevices(processDevices devicesCallback)
{
#ifdef SPOTIFY_DEBUG
Serial.println(SPOTIFY_DEVICES_ENDPOINT);
printStack();
#endif
// Get from https://arduinojson.org/v6/assistant/
const size_t bufferSize = getDevicesBufferSize;
if (autoTokenRefresh)
{
checkAndRefreshAccessToken();
}
int statusCode = makeGetRequest(SPOTIFY_DEVICES_ENDPOINT, _bearerToken);
#ifdef SPOTIFY_DEBUG
Serial.print("Status Code: ");
Serial.println(statusCode);
#endif
if (statusCode > 0)
{
skipHeaders();
}
if (statusCode == 200)
{
// Allocate DynamicJsonDocument
DynamicJsonDocument doc(bufferSize);
// Parse JSON object
#ifndef SPOTIFY_PRINT_JSON_PARSE
DeserializationError error = deserializeJson(doc, *client);
#else
ReadLoggingStream loggingStream(*client, Serial);
DeserializationError error = deserializeJson(doc, loggingStream);
#endif
if (!error)
{
uint8_t totalDevices = doc["devices"].size();
SpotifyDevice spotifyDevice;
for (int i = 0; i < totalDevices; i++)
{
JsonObject device = doc["devices"][i];
spotifyDevice.id = device["id"].as<const char *>();
spotifyDevice.name = device["name"].as<const char *>();
spotifyDevice.type = device["type"].as<const char *>();
spotifyDevice.isActive = device["is_active"].as<bool>();
spotifyDevice.isPrivateSession = device["is_private_session"].as<bool>();
spotifyDevice.isRestricted = device["is_restricted"].as<bool>();
spotifyDevice.volumePercent = device["volume_percent"].as<int>();
if (!devicesCallback(spotifyDevice, i, totalDevices))
{
//User has indicated they are finished.
break;
}
}
}
else
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
#endif
statusCode = -1;
}
}
closeClient();
return statusCode;
}
int SpotifyArduino::commonGetImage(char *imageUrl)
{
#ifdef SPOTIFY_DEBUG
Serial.print(F("Parsing image URL: "));
Serial.println(imageUrl);
#endif
uint8_t lengthOfString = strlen(imageUrl);
// We are going to just assume https, that's all I've
// seen and I can't imagine a company will go back
// to http
if (strncmp(imageUrl, "https://", 8) != 0)
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.print(F("Url not in expected format: "));
Serial.println(imageUrl);
Serial.println("(expected it to start with \"https://\")");
#endif
return false;
}
uint8_t protocolLength = 8;
char *pathStart = strchr(imageUrl + protocolLength, '/');
uint8_t pathIndex = pathStart - imageUrl;
uint8_t pathLength = lengthOfString - pathIndex;
char path[pathLength + 1];
strncpy(path, pathStart, pathLength);
path[pathLength] = '\0';
uint8_t hostLength = pathIndex - protocolLength;
char host[hostLength + 1];
strncpy(host, imageUrl + protocolLength, hostLength);
host[hostLength] = '\0';
#ifdef SPOTIFY_DEBUG
Serial.print(F("host: "));
Serial.println(host);
Serial.print(F("len:host:"));
Serial.println(hostLength);
Serial.print(F("path: "));
Serial.println(path);
Serial.print(F("len:path: "));
Serial.println(strlen(path));
#endif
int statusCode = makeGetRequest(path, NULL, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", host);
#ifdef SPOTIFY_DEBUG
Serial.print(F("statusCode: "));
Serial.println(statusCode);
#endif
if (statusCode == 200)
{
return getContentLength();
}
// Failed
return -1;
}
bool SpotifyArduino::getImage(char *imageUrl, Stream *file)
{
int totalLength = commonGetImage(imageUrl);
#ifdef SPOTIFY_DEBUG
Serial.print(F("file length: "));
Serial.println(totalLength);
#endif
if (totalLength > 0)
{
skipHeaders(false);
int remaining = totalLength;
// This section of code is inspired but the "Web_Jpg"
// example of TJpg_Decoder
// https://github.com/Bodmer/TJpg_Decoder
// -----------
uint8_t buff[128] = {0};
while (client->connected() && (remaining > 0 || remaining == -1))
{
// Get available data size
size_t size = client->available();
if (size)
{
// Read up to 128 bytes
int c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// Write it to file
file->write(buff, c);
// Calculate remaining bytes
if (remaining > 0)
{
remaining -= c;
}
}
yield();
}
// ---------
#ifdef SPOTIFY_DEBUG
Serial.println(F("Finished getting image"));
#endif
}
closeClient();
return (totalLength > 0); //Probably could be improved!
}
bool SpotifyArduino::getImage(char *imageUrl, uint8_t **image, int *imageLength)
{
int totalLength = commonGetImage(imageUrl);
#ifdef SPOTIFY_DEBUG
Serial.print(F("file length: "));
Serial.println(totalLength);
#endif
if (totalLength > 0)
{
skipHeaders(false);
uint8_t *imgPtr = (uint8_t *)malloc(totalLength);
*image = imgPtr;
*imageLength = totalLength;
int remaining = totalLength;
int amountRead = 0;
#ifdef SPOTIFY_DEBUG
Serial.println(F("Fetching Image"));
#endif
// This section of code is inspired but the "Web_Jpg"
// example of TJpg_Decoder
// https://github.com/Bodmer/TJpg_Decoder
// -----------
uint8_t buff[128] = {0};
while (client->connected() && (remaining > 0 || remaining == -1))
{
// Get available data size
size_t size = client->available();
if (size)
{
// Read up to 128 bytes
int c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// Write it to file
memcpy((uint8_t *)imgPtr + amountRead, (uint8_t *)buff, c);
// Calculate remaining bytes
if (remaining > 0)
{
amountRead += c;
remaining -= c;
}
}
yield();
}
// ---------
#ifdef SPOTIFY_DEBUG
Serial.println(F("Finished getting image"));
#endif
}
closeClient();
return (totalLength > 0); //Probably could be improved!
}
int SpotifyArduino::getContentLength()
{
if (client->find("Content-Length:"))
{
int contentLength = client->parseInt();
#ifdef SPOTIFY_DEBUG
Serial.print(F("Content-Length: "));
Serial.println(contentLength);
#endif
return contentLength;
}
return -1;
}
void SpotifyArduino::skipHeaders(bool tossUnexpectedForJSON)
{
// Skip HTTP headers
if (!client->find("\r\n\r\n"))
{
#ifdef SPOTIFY_SERIAL_OUTPUT
Serial.println(F("Invalid response"));
#endif
return;
}
if (tossUnexpectedForJSON)
{
// Was getting stray characters between the headers and the body
// This should toss them away
while (client->available() && client->peek() != '{')
{
char c = 0;
client->readBytes(&c, 1);
#ifdef SPOTIFY_DEBUG
Serial.print(F("Tossing an unexpected character: "));
Serial.println(c);
#endif
}
}
}
int SpotifyArduino::getHttpStatusCode()
{
char status[32] = {0};
client->readBytesUntil('\r', status, sizeof(status));
#ifdef SPOTIFY_DEBUG
Serial.print(F("Status: "));
Serial.println(status);
#endif
char *token;
token = strtok(status, " "); // https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
#ifdef SPOTIFY_DEBUG
Serial.print(F("HTTP Version: "));
Serial.println(token);
#endif
if (token != NULL && (strcmp(token, "HTTP/1.0") == 0 || strcmp(token, "HTTP/1.1") == 0))
{
token = strtok(NULL, " ");
if (token != NULL)
{
#ifdef SPOTIFY_DEBUG
Serial.print(F("Status Code: "));
Serial.println(token);
#endif
return atoi(token);
}
}
return -1;
}
void SpotifyArduino::parseError()
{
//This method doesn't currently do anything other than print
#ifdef SPOTIFY_SERIAL_OUTPUT
DynamicJsonDocument doc(1000);
DeserializationError error = deserializeJson(doc, *client);
if (!error)
{
Serial.print(F("getAuthToken error"));
serializeJson(doc, Serial);
}
else
{
Serial.print(F("Could not parse error"));
}
#endif
}
void SpotifyArduino::closeClient()
{
if (client->connected())
{
#ifdef SPOTIFY_DEBUG
Serial.println(F("Closing client"));
#endif
client->stop();
}
}
#ifdef SPOTIFY_DEBUG
void SpotifyArduino::printStack()
{
char stack;
Serial.print(F("stack size "));
Serial.println(stack_start - &stack);
}
#endif
I've created a new branch, please try that and post the serial output.
https://github.com/witnessmenow/spotify-api-arduino/tree/crashDebug%2333
.....
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=AQB8MslRtrbAb_W3NjuXkNaQ5RuD7oQ_5VFymPIOiq7fblbH1R9kmkWIx0VMKu8QoU-2yprBPwU7vx4mhOsPnBgQ8JSRhVuLVZi6KB2k5k4Xmv8TgQuGvuCra9bTCaBRDUY&client_id=f8aeea367669458dac14b17261ff61ea&client_secret=19cacb238db34764913ab16b7a210b98
stack size -1073421743
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Inside statusCode == 200
Allocated Json
{"access_token":"BQByg4z5lWwuScztGNcftr8yO88-FZKWADiNFUs27sQA6uoO38w9iCeaMntrD2o7CYfdHzZKz3n7uM1x-_hzxSJ2BlMDrakMZ-M6pJvW8kBUC96bPB5gRYQoZonAcZ2XIr3dSjYcxi6Vhh00I_ksHItM0JFKTTvmXwJQkphNXe-ECa1wsrJw0HslNWeNnPQddqSxryJDEJwDn1IysbtCnCUcWbqrAqZmC4D-uIKeKTOORhJsNiah0TIfKqBpefp2G1ai-5scOOHRIu_ANabn-qjVcj4-y3fVV5KINyt3gxlxcNm3Sw","token_type":"Bearer","expires_in":3600,"scope":"playlist-read-private playlist-read-collaborative ugc-image-upload user-follow-read playlist-modify-private user-read-email user-read-private app-remote-control user-follow-modify user-modify-playback-state user-library-read user-library-modify playlist-modify-public user-read-playback-state user-read-currently-playing user-read-recently-played user-read-playback-position user-top-read"}Finished JSON deserilaize
No error
End of no error
Before Close client
In Close client
Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x00667ec0 PS : 0x00060e30 A0 : 0x800d4c41 A1 : 0x3ffb1db0
A2 : 0x3ffc1764 A3 : 0x3ffc1a18 A4 : 0x000000a0 A5 : 0xa793ee40
A6 : 0x3ffb1cb0 A7 : 0x3f400da2 A8 : 0x800d304b A9 : 0x3ffb1d90
A10 : 0x3ffc1864 A11 : 0x0000000f A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000014
EXCVADDR: 0x00667ec0 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffc
ELF file SHA256: 0000000000000000
Backtrace: 0x00667ec0:0x3ffb1db0 0x400d4c3e:0x3ffb1dd0 0x400d0b72:0x3ffb1f70 0x400d5f12:0x3ffb1fb0 0x400897b2:0x3ffb1fd0
Rebooting...
And decoded
PC: 0x00667ec0
EXCVADDR: 0x00667ec0
Decoding stack results
0x400d4c3e: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-crashDebug-33\src\SpotifyArduino.cpp line 228
0x400d0b72: setup() at C:\Users\DAVIDC~1\AppData\Local\Temp\arduino_modified_sketch_365107/getCurrentlyPlaying.ino line 114
0x400d5f12: loopTask(void*) at C:\Users\David Calderon\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\cores\esp32\main.cpp line 18
0x400897b2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Ok we have narrowed down where it crashes,
client->isConnected()
, the problem is why would it crash there, it makes no sense. And there is still the problem of why it works for everyone else and not for you
Can you try downgrade your version of esp32 core to 1.05? (Go to board manager, search for esp32 and there is a version drop down)
Or might be even easier to use a portable version of the Arduino ide so you don't have to impact what you currently have:
Same, I've downgraded to 1.0.5 and:
...
Connected to haifisch
IP address: 192.168.1.137
Refreshing Access Tokens
grant_type=refresh_token&refresh_token=AQB8MslRtrbAb_W3NjuXkNaQ5RuD7oQ_5VFymPIOiq7fblbH1R9kmkWIx0VMKu8QoU-2yprBPwU7vx4mhOsPnBgQ8JSRhVuLVZi6KB2k5k4Xmv8TgQuGvuCra9bTCaBRDUY&client_id=f8aeea367669458dac14b17261ff61ea&client_secret=19cacb238db34764913ab16b7a210b98
stack size -1073421743
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Inside statusCode == 200
Allocated Json
{"access_token":"BQBwQT5kpmgDJnVUIbJIYQMECeysX3FsC3RfB-No1gsz89dDrr3sD71pJQG4aWIQv0hBAuBu_tHXUmu0XOR3n2EA9jBtfs5h2DyOBfpUb2vnOi29Y0LJbo5NH2_7blSEIvxy3fii8KJMzlbPDry0SRBp42Z_XqClOlTz7Ha8sHMm6_eKC1tSRZJpM2WoDl2Nlpjk_XoQoUWwDrLQdmk7VPkNpTV4oLOAr3IMSHrcWH3eB3AHgKJFRQJE1NXVTrX82UIsNrwrjzk7CIB8VUM-ixZaSKwLl-cw8YRkP8HSlGzauJITbw","token_type":"Bearer","expires_in":3600,"scope":"playlist-read-private playlist-read-collaborative ugc-image-upload user-follow-read playlist-modify-private user-read-email user-read-private app-remote-control user-follow-modify user-modify-playback-state user-library-read user-library-modify playlist-modify-public user-read-playback-state user-read-currently-playing user-read-recently-played user-read-playback-position user-top-read"}Finished JSON deserilaize
No error
End of no error
Before Close client
In Close client
Guru Meditation Error: Core 1 panic'ed (IllegalInstruction). Exception was unhandled.
Core 1 register dump:
PC : 0x667ec000 PS : 0x00060e30 A0 : 0x800d535d A1 : 0x3ffb1db0
A2 : 0x3ffc176c A3 : 0x3ffc1a20 A4 : 0x000000a0 A5 : 0xb89f24b0
A6 : 0x3ffb1cb0 A7 : 0x3f400da2 A8 : 0x800d3777 A9 : 0x3ffb1d90
A10 : 0x3ffc186c A11 : 0x0000000f A12 : 0x00000000 A13 : 0x3f400ad1
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000000
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffc
ELF file SHA256: 0000000000000000
Backtrace: 0x667ec000:0x3ffb1db0 0x400d535a:0x3ffb1dd0 0x400d12de:0x3ffb1f70 0x400d660a:0x3ffb1fb0 0x400897a2:0x3ffb1fd0
Rebooting...
Decoded
PC: 0x667ec000
EXCVADDR: 0x00000000
Decoding stack results
0x400d535a: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-crashDebug-33\src\SpotifyArduino.cpp line 228
0x400d12de: setup() at C:\Users\DAVIDC~1\AppData\Local\Temp\arduino_modified_sketch_279483/getCurrentlyPlaying.ino line 114
0x400d660a: loopTask(void*) at C:\Users\David Calderon\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5\cores\esp32\main.cpp line 32
0x400897a2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Can you try change the setup of your sketch to remove the part where it calls refreshAccessToken? Just comment it out like below or remove it.
The library will automatically detect you dont have a valid one when you make another call and try refresh it. I see some difference to what gets printed out on the serial monitor when using both which I'll need to look into.
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Handle HTTPS Verification
#if defined(ESP8266)
client.setFingerprint(SPOTIFY_FINGERPRINT); // These expire every few months
#elif defined(ESP32)
client.setCACert(spotify_server_cert);
#endif
// ... or don't!
//client.setInsecure();
// If you want to enable some extra debugging
// uncomment the "#define SPOTIFY_DEBUG" in ArduinoSpotify.h
// Serial.println("Refreshing Access Tokens");
// if (!spotify.refreshAccessToken())
// {
// Serial.println("Failed to get access tokens");
// }
}
Done.
.
Connected to haifisch
IP address: 192.168.1.137
Free Heap: 280600
getting currently playing song:
/v1/me/player/currently-playing?market=ES
stack size -1073421311
Refresh of the Access token is due, doing that now.
grant_type=refresh_token&refresh_token=AQB8MslRtrbAb_W3NjuXkNaQ5RuD7oQ_5VFymPIOiq7fblbH1R9kmkWIx0VMKu8QoU-2yprBPwU7vx4mhOsPnBgQ8JSRhVuLVZi6KB2k5k4Xmv8TgQuGvuCra9bTCaBRDUY&client_id=f8aeea367669458dac14b17261ff61ea&client_secret=19cacb238db34764913ab16b7a210b98
stack size -1073420863
accounts.spotify.com
Status: HTTP/1.0 200 OK
HTTP Version: HTTP/1.0
Status Code: 200
status Code200
Inside statusCode == 200
Allocated Json
{"access_token":"BQBzUQCgBLNlRo08wH35Dom49JZsDXLlBqVhOob8g2uT5VTBSjG-lXIvJw6W6C79M2s7_YYVagZ7NcaJxudChvCngwC3Ir4eI5lcQyb4BDZoBINtT138_kwGvAe8KRM7NlvXX03V6WRP9Ns__g2-Pr8P6pSJ_2e9IHd8UOSmtGSqrvpG7mcP3lxnCgdSZGAuPSanywxFNH6H3mKs2jvOuxSsV9gL0TlFxIP6ZYUhmSS65R-SJIofiSNj93XGmsRnVNZI3iOxWRAbi2uDZ5vr8iSbICIiUCE4MoBZsmJDXZn6-cdqoQ","token_type":"Bearer","expires_in":3600,"scope":"playlist-read-private playlist-read-collaborative ugc-image-upload user-follow-read playlist-modify-private user-read-email user-read-private app-remote-control user-follow-modify user-modify-playback-state user-library-read user-library-modify playlist-modify-public user-read-playback-state user-read-currently-playing user-read-recently-played user-read-playback-position user-top-read"}Finished JSON deserilaize
No error
End of no error
Before Close client
In Close client
Guru Meditation Error: Core 1 panic'ed (IllegalInstruction). Exception was unhandled.
Core 1 register dump:
PC : 0x667ec000 PS : 0x00060230 A0 : 0x800d5339 A1 : 0x3ffb1a40
A2 : 0x3ffc176c A3 : 0x3ffc1a20 A4 : 0x000000a0 A5 : 0x80fb61ad
A6 : 0x3ffb1940 A7 : 0x3f400d6e A8 : 0x800d3753 A9 : 0x3ffb1a20
A10 : 0x3ffc186c A11 : 0x0000000f A12 : 0x00000000 A13 : 0x3f400a9d
A14 : 0x00000132 A15 : 0x00000001 SAR : 0x0000000a EXCCAUSE: 0x00000000
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xfffffffc
ELF file SHA256: 0000000000000000
Backtrace: 0x667ec000:0x3ffb1a40 0x400d5336:0x3ffb1a60 0x400d538d:0x3ffb1c00 0x400d541e:0x3ffb1c20 0x400d130d:0x3ffb1f90 0x400d65f5:0x3ffb1fb0 0x400897a2:0x3ffb1fd0
Rebooting...
Decoded:
PC: 0x667ec000
EXCVADDR: 0x00000000
Decoding stack results
0x400d5336: SpotifyArduino::refreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-crashDebug-33\src\SpotifyArduino.cpp line 228
0x400d538d: SpotifyArduino::checkAndRefreshAccessToken() at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-crashDebug-33\src\SpotifyArduino.cpp line 240
0x400d541e: SpotifyArduino::getCurrentlyPlaying(void (*)(CurrentlyPlaying), char const*) at C:\Users\David Calderon\Documents\Arduino\libraries\spotify-api-arduino-crashDebug-33\src\SpotifyArduino.cpp line 504
0x400d130d: loop() at C:\Users\DAVIDC~1\AppData\Local\Temp\arduino_modified_sketch_142759/getCurrentlyPlaying.ino line 211
0x400d65f5: loopTask(void*) at C:\Users\David Calderon\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.5\cores\esp32\main.cpp line 37
0x400897a2: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143
Ok, I have figured the problem out. Your access_token
(one of the responses from that request) is way longer than mine and it is causing a memory overflow
Mine is ~170 characters long, yours is ~300 characters. The buffer that this eventually lives was only 200 characters and I never checked for an overflow, because I never expected the length of an access token to vary from person to person! Expect the unexpected I guess!
The branch has been updated with code that should solve this issue for you.
How did you get your RefreshToken?
Cause in my response for the same method my scope returns as:
"scope": "user-modify-playback-state user-read-playback-state user-read-email user-read-private"
yours returns as:
"scope":"playlist-read-private playlist-read-collaborative ugc-image-upload user-follow-read playlist-modify-private user-read-email user-read-private app-remote-control user-follow-modify user-modify-playback-state user-library-read user-library-modify playlist-modify-public user-read-playback-state user-read-currently-playing user-read-recently-played user-read-playback-position user-top-read"
Note: Please refresh your client secret in the Spotify Development console as currently people have access to your account
Awsome!!
Worked like a charm!!
Good to hear
Hi, I am trying the getCurrentlyPlaying, with a refresh_token got from the getRefreshToken example; and it always brings up the same error:
Connected to haifisch IP address: 192.168.1.137 Refreshing Access Tokens grant_type=refresh_token&refresh_token=AQB_zX3KKxiYsogl26g4LNqXvyHJ5iR2pdT1Cc8p2uxQKEC2QybHZinD7-GF47VbXc4_c612bkVmWtjQKE4VYx8amK3m25DAv2NdEjk3NA3iM29noOn3YGwpHigM-WXSrqA&client_id=f8aeea367669458dac14b17261ff61ea&client_secret=12b50f86299943a6b7b1152eb343420d stack size -1073421775 accounts.spotify.com Status Code: 200 status Code200 Closing client Free Heap: 278432 getting currently playing song: /v1/me/player/currently-playing?market=ES stack size -1073421711 Status Code: -1 stack size -1073421711 Closing client