witnessmenow / spotify-api-arduino

Arduino library for integrating with the Spotify Web-API (Does not play music)
MIT License
178 stars 33 forks source link

Not Library related #56

Open GrimorJander opened 1 year ago

GrimorJander commented 1 year ago

Hi Brian, first thank you for your work. I have implemented your Spotify api in order to show current track name and artist on a rgb matrix display (single 64x32 module with esp32 hub75 / Mrfaptastic library ).

Although in principle it works correctly, I can't show the name of the artist with dma_display->print(currentlyPlaying.artists[i].artistName); I get compiling error with this funtion on RGB matrix display (on serial monitor is just fine)ç

Another help that I would like to ask you, is if it is possible to make the text scroll since there is not space for so much information in a simple panel.

Thanks in advance

`// ---------------------------- // Standard Libraries // ----------------------------

if defined(ESP8266)

include

elif defined(ESP32)

include

endif

include

include

include

include

include

include

include "Fonts/FreeSansBold9pt7b.h"

include "Fonts/FreeSansBold12pt7b.h"

include "Fonts/FreeSansBold18pt7b.h"

include "Fonts/Picopixel.h"

include "Fonts/FreeSerif9pt7b.h"

include "Fonts/FreeSerif12pt7b.h"

include "Fonts/FreeSerif18pt7b.h"

//#include "Fonts/FreeSerif12pt7b.h"

include

include

// ---------------------------- // Additional Libraries - each one of these will need to be installed. // ----------------------------

include

// 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

include

// 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[] = "MiFibra-XXXX"; // your network SSID (name) char password[] = "XXXXXXX"; // your network password char clientId[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Your client ID of your spotify APP char clientSecret[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Your client Secret of your spotify APP (Do Not share this!)

// Country code, including this is advisable

define SPOTIFY_MARKET "IE"

define SPOTIFY_REFRESH_TOKEN "AQBn5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx--D4oPfCCMaXZAnQqBcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxaO4"

//------- ---------------------- ------ // ------------------------------------- // ------- Matrix Config ------ // -------------------------------------

const int panelResX = 64; // Number of pixels wide of each INDIVIDUAL panel module. const int panelResY = 32; // Number of pixels tall of each INDIVIDUAL panel module. const int panel_chain = 1; // Total number of panels chained one to another

define ENABLE_DOUBLE_BUFFER 1 // This is a good example to show the difference the //estaba quitado originalmente

// double buffer makes, it doesn't flash as much // comment this out to test without it

// See the "displaySetup" method for more display config options

//------------------------------------------------------------------------------------------------------------------

MatrixPanel_I2S_DMA *dma_display = nullptr;

WiFiClientSecure secured_client;

uint16_t myBLACK = dma_display->color565(0, 0, 0); uint16_t myWHITE = dma_display->color565(255, 255, 255); uint16_t myRED = dma_display->color565(255, 0, 0); uint16_t myGREEN = dma_display->color565(0, 255, 0); uint16_t myBLUE = dma_display->color565(0, 0, 255); uint16_t myPINK = dma_display->color565(227, 28, 121); uint16_t myYELLOW = dma_display->color565(255, 255, 0); uint16_t myPURPLE = dma_display->color565(199, 36, 177);

void displaySetup() { HUB75_I2S_CFG mxconfig( panelResX, // module width panelResY, // module height panel_chain // Chain length );

ifdef ENABLE_DOUBLE_BUFFER

// This is how you enable the double buffer. // Double buffer can help with animation heavy projects mxconfig.double_buff = false;

endif

mxconfig.clkphase = false;

dma_display = new MatrixPanel_I2S_DMA(mxconfig); dma_display->begin(); }

TaskHandle_t Task1;

WiFiClientSecure client; SpotifyArduino spotify(client, clientId, clientSecret, SPOTIFY_REFRESH_TOKEN);

unsigned long delayBetweenRequests = 6000; // Time between requests (1 minute) unsigned long requestDueTime; //time when request due

void setup() {

Serial.begin(115200);

displaySetup();

dma_display->fillScreen(myBLACK); dma_display->setFont(&FreeSansBold9pt7b); dma_display->setCursor(0,20); dma_display->setTextSize(1); // size 2 == 16 pixels high dma_display->setTextWrap(false); // N.B!! Don't wrap at end of line dma_display->setTextColor(myWHITE);

ifdef ENABLE_DOUBLE_BUFFER

dma_display->flipDMABuffer();

endif

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

Serial.println("Refreshing Access Tokens");
if (!spotify.refreshAccessToken())
{
    Serial.println("Failed to get access tokens");
}

}

void printCurrentlyPlayingToSerial(CurrentlyPlaying currentlyPlaying) { Serial.print("Track: "); Serial.println(currentlyPlaying.trackName);

dma_display->fillScreen(myBLACK);
dma_display->setCursor(0,20); 
dma_display->print(currentlyPlaying.trackName);

Serial.println("Artist: ");
for (int i = 0; i < currentlyPlaying.numArtists; i++)
{
    Serial.print("Name: ");
    Serial.println(currentlyPlaying.artists[i].artistName);
    //Serial.print("Artist URI: ");
    //Serial.println(currentlyPlaying.artists[i].artistUri);
    Serial.println();
}

}

void loop() {

ifdef ENABLE_DOUBLE_BUFFER

dma_display->flipDMABuffer();

endif

if (millis() > requestDueTime) {

    Serial.println("getting currently playing song:");
    // Market can be excluded if you want e.g. spotify.getCurrentlyPlaying()
    int status = spotify.getCurrentlyPlaying(printCurrentlyPlayingToSerial, SPOTIFY_MARKET);
    if (status == 200)
    {
        Serial.println("Successfully got currently playing");
    }
    else if (status == 204)
    {
        Serial.println("Doesn't seem to be anything playing");
    }
    else
    {
        Serial.print("Error: ");
        Serial.println(status);
    }
    requestDueTime = millis() + delayBetweenRequests;
}

}`

GrimorJander commented 1 year ago

IMG_20230419_080106

witnessmenow commented 1 year ago

Hello,

Part 1 of your question. I'm surprised dma_display->print(currentlyPlaying.artists[i].artistName); didn't work, what was the compile error?

Part 2: yeah they are very limited for space ok! I have a scrolling text example on the Trinity Github repo that should hopefully help

https://github.com/witnessmenow/ESP32-Trinity/blob/master/examples/BuildingBlocks/Text/ScrollingText/ScrollingText.ino

it should be simple enough to modify this to use spotify

inside your spotify callback just update the text variable and reset it's position

void printCurrentlyPlayingToSerial(CurrentlyPlaying currentlyPlaying)
{
    Serial.print("Track: ");
    Serial.println(currentlyPlaying.trackName);

    String tempText = String(currentlyPlaying.trackName);
    if(text != tempText){ //only update the text if the track name has changed
        text = tempText;
        textXPosition = 64; //This will start the text off to the right of the screen again
    }

}

A couple of thoughts around this:

  1. You may need to modify this example to display more than one bit of information. I would recommend getting this logic working before integrating spotify into the flow.
  2. Checking spotify will hog the ESP processor, which will stop the scrolling, so maybe limit checking spotify to when text is off screen (Or move the scrolling and display logic to the second ESP32 core, but that is more complicated)
GrimorJander commented 1 year ago

Thank you very much for your advice. I apologize because I am very new to programming and it is difficult for me to make changes that do not result in compilation errors. Tomorrow morning I'll try what you suggest, in the office. I normally put music on spotify to my colleagues and they often ask me the names of artists they don't know. It's very funny, because currently we all use another of your APIs (telegram-api bot ) to send us scrolling messages in the office since we all share the same Bot. If you ever visit Malaga, I already owe you several beers!!

GrimorJander commented 1 year ago

Part 1 of your question. I'm surprised dma_display->print(currentlyPlaying.artists[i].artistName); didn't work, what was the compile error?

The error is: currentlyPlaying' was not declared in this scope , when i try to put on both setup or loop part of the code.

However, dma_display->print(currentlyPlaying.trackName); seens to work OK in the Void Setup part, but no on the loop part.

So, i think i need those funtions working on the loop part in order to integrate with your Trinity - scroll skecht (that works like a charm)

GrimorJander commented 1 year ago

This is the close i can get: Img alt text Youtube link: https://youtu.be/8d21nvXapiw

Where cursor seens to be scrolling as expected, i can only draw 1 time track name every spotify callback, so i put 1 second between calls. really laggy result this way.

`// ---------------------------- // Standard Libraries // ----------------------------

if defined(ESP8266)

include

elif defined(ESP32)

include

endif

include

include

include

include

include

include

include "Fonts/FreeSansBold9pt7b.h"

include "Fonts/FreeSansBold12pt7b.h"

include "Fonts/FreeSansBold18pt7b.h"

include "Fonts/Picopixel.h"

include "Fonts/FreeSerif9pt7b.h"

include "Fonts/FreeSerif12pt7b.h"

include "Fonts/FreeSerif18pt7b.h"

include "Fonts/FreeSerifBold9pt7b.h"

include

include

include

// ---------------------------- // Additional Libraries - each one of these will need to be installed. // ----------------------------

include

// 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

include

// 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[] = "MiFibra-XXXX"; // your network SSID (name) char password[] = "XXXXXXXX"; // your network password

define BOT_TOKEN "57XXXXXXXXXXXXXXXL__pTXXXXXXXXXXXA"

char clientId[] = "35XXXXXXXXXXXXXXXXXXXXXXXXXX6"; // Your client ID of your spotify APP char clientSecret[] = "d5XXXXXXXXXXXXXXXXXXXXXXXXXd8"; // Your client Secret of your spotify APP (Do Not share this!)

// Country code, including this is advisable

define SPOTIFY_MARKET "IE"

define SPOTIFY_REFRESH_TOKEN bxEyrT4p8fXXXXXXXXXXXXXXXXXXXXXXXXZKpbaO4"

//------- ---------------------- ------ // ------------------------------------- // ------- Matrix Config ------ // -------------------------------------

const int panelResX = 64; // Number of pixels wide of each INDIVIDUAL panel module. const int panelResY = 32; // Number of pixels tall of each INDIVIDUAL panel module. const int panel_chain = 1; // Total number of panels chained one to another

define ENABLE_DOUBLE_BUFFER 1 // This is a good example to show the difference the //estaba quitado originalmente

// double buffer makes, it doesn't flash as much // comment this out to test without it

// See the "displaySetup" method for more display config options

//------------------------------------------------------------------------------------------------------------------

MatrixPanel_I2S_DMA *dma_display = nullptr;

// For scrolling Text unsigned long isAnimationDue; int delayBetweeenAnimations = 25; // Smaller == faster

int textXPosition = panelResX * panel_chain; // Will start off screen int textYPosition = panelResY / 2 - 8; // center of screen - 8 (half of the text height)

String text = "ESP32 Trinity, by Brian Lough";

WiFiClientSecure secured_client;

uint16_t myBLACK = dma_display->color565(0, 0, 0); uint16_t myWHITE = dma_display->color565(255, 255, 255); uint16_t myRED = dma_display->color565(255, 0, 0); uint16_t myGREEN = dma_display->color565(0, 255, 0); uint16_t myBLUE = dma_display->color565(0, 0, 255); uint16_t myPINK = dma_display->color565(227, 28, 121); uint16_t myYELLOW = dma_display->color565(255, 255, 0); uint16_t myPURPLE = dma_display->color565(199, 36, 177);

void displaySetup() { HUB75_I2S_CFG mxconfig( panelResX, // module width panelResY, // module height panel_chain // Chain length );

ifdef ENABLE_DOUBLE_BUFFER

// This is how you enable the double buffer. // Double buffer can help with animation heavy projects mxconfig.double_buff = false;

endif

mxconfig.clkphase = false;

dma_display = new MatrixPanel_I2S_DMA(mxconfig); dma_display->begin(); }

TaskHandle_t Task1;

WiFiClientSecure client; SpotifyArduino spotify(client, clientId, clientSecret, SPOTIFY_REFRESH_TOKEN);

unsigned long delayBetweenRequests = 1000; // Time between requests (1 minute) unsigned long requestDueTime; //time when request due

void setup() {

Serial.begin(115200); displaySetup();

dma_display->fillScreen(myBLACK); //dma_display->setFont(&FreeSerifBold9pt7b); dma_display->setTextSize(2); // size 2 == 16 pixels high dma_display->setTextWrap(false); // N.B!! Don't wrap at end of line dma_display->setTextColor(myWHITE);

ifdef ENABLE_DOUBLE_BUFFER

dma_display->flipDMABuffer();

endif

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

Serial.println("Refreshing Access Tokens"); if (!spotify.refreshAccessToken()) { Serial.println("Failed to get access tokens"); } }

void printCurrentlyPlayingToSerial(CurrentlyPlaying currentlyPlaying) { Serial.print("Track: "); Serial.println(currentlyPlaying.trackName);

dma_display->fillScreen(myBLACK); //dma_display->setCursor(0,20); dma_display->print(currentlyPlaying.trackName);

Serial.println("Artist: "); for (int i = 0; i < currentlyPlaying.numArtists; i++) { Serial.print("Name: "); Serial.println(currentlyPlaying.artists[i].artistName); //Serial.print("Artist URI: "); //Serial.println(currentlyPlaying.artists[i].artistUri); Serial.println(); } }

// Will be used in getTextBounds. int16_t xOne, yOne; uint16_t w, h;

void loop() {

unsigned long now = millis(); if (now > isAnimationDue) { isAnimationDue = now + delayBetweeenAnimations;

textXPosition -= 1;

// Checking is the very right of the text off screen to the left
dma_display->getTextBounds(text, textXPosition, textYPosition, &xOne, &yOne, &w, &h);
if (textXPosition + w <= 0)
{
  textXPosition = 64;
}

dma_display->setCursor(textXPosition, textYPosition);

// The display has to do less updating if you only black out the area
// the text is
//dma_display->fillScreen(myBLACK);
//dma_display->fillRect(0, textYPosition, dma_display->width(), 16, myBLACK);

// dma_display->print(text);

ifdef ENABLE_DOUBLE_BUFFER

dma_display->flipDMABuffer();

endif

}

ifdef ENABLE_DOUBLE_BUFFER

dma_display->flipDMABuffer();

endif

if (millis() > requestDueTime) {

Serial.println("getting currently playing song:");
// Market can be excluded if you want e.g. spotify.getCurrentlyPlaying()

// int status = spotify.getCurrentlyPlaying(printCurrentlyPlayingToSerial, SPOTIFY_MARKET); int status = spotify.getCurrentlyPlaying(printCurrentlyPlayingToSerial); if (status == 200) { Serial.println("Successfully got currently playing"); } else if (status == 204) { Serial.println("Doesn't seem to be anything playing"); } else { Serial.print("Error: "); Serial.println(status); } requestDueTime = millis() + delayBetweenRequests; } } `