Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Andres SabasCarlos Alatorre
Published

Spotify & NeoPixel Controller

Intuitive control of Spotify using Arduino MKR IoT Carrier

IntermediateFull instructions provided1,437
Spotify & NeoPixel Controller

Things used in this project

Hardware components

CatSink USB-C PD
Electronic Cats CatSink USB-C PD
×1
Arduino MKR WiFi 1010
Arduino MKR WiFi 1010
×1
Arduino MKR IoT Carrier
×1

Software apps and online services

Arduino Web Editor
Arduino Web Editor

Story

Read more

Code

Spotify_and_NeoPixel_Controller.ino

Arduino
Main code
#include "arduino_secrets.h"
#include <ArduinoJson.h>    //Mejor manejo de la memoria, Better memory managment
#include <ArduinoHttpClient.h>
#include <Arduino_MKRIoTCarrier.h>
#include <Adafruit_NeoPixel.h>

#include "thingProperties.h"//Necesario para conexion a internet //Needed to conect to internt
#include "Logo.h"           //Se vincula el archivo donde esta nuestra imagen en C //Our imagen in C
#include "pitches.h"

//Configuracion de NeoPixel //NeoPixel variables
#define pin 5
#define numPixels 118
Adafruit_NeoPixel pixels(numPixels, pin, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 50

//Melodia que se tocara en el buzzer, Buzzer melody
/*int melody[] = {
 NOTE_C5, NOTE_G4, NOTE_E4, NOTE_A4, NOTE_B4, NOTE_A4, 
 NOTE_GS4, NOTE_AS4, NOTE_GS4, NOTE_G4, NOTE_D4, NOTE_E4
}; //Cancion de game over Super Mario //Super Mario's Game Over melody

//Duacion de las notas: 4 = cuarto de nota, 8 = octavo de nota, etc., Notes duration
int noteDurations[] = {
  4, 4, 4, 8, 8, 8, 
  8, 8, 8, 8, 8, 2
};*/

//Configuracion de Spotify, Spotify config
enum DrawnState { None, Play, Pause };

const char SPOTIFY_CLIENT[] = SECRET_SPOTIFY_CLIENT;  // Cliente ID de la aplicacion de Spotify, Spotify Client ID
const char SPOTIFY_SECRET[] = SECRET_SPOTIFY_SECRET;  // Cliente secreto de la aplicacion de Spotify, Spotify Secret Client
const unsigned long TOKEN_REFRESH_RATE = 3000000; 
const unsigned long UPDATE_REFRESH_RATE = 500;

//Web Server para autorizacion , Authentication web server
WiFiServer server(80);  // Servidor para autorizacion de Spotify, Web server initalization 
WiFiSSLClient ssl;      // Cliente para peticiones HTTPS de Spotify , HTTPS client for Spotify requests
HttpClient authClient = HttpClient(ssl, "accounts.spotify.com", 443);
HttpClient apiClient = HttpClient(ssl, "api.spotify.com", 443);
MKRIoTCarrier carrier; //Incialia el carrier y le da nombre "carrier" , Start the carrier and name it

String accessToken;
String refreshToken;
bool authenticated = false;
unsigned long lastTokenTime = 0;
unsigned long lastTrackTime = 0;
int songProgress = 0;
DrawnState lastDrawnState = None;

//-----------------------------UTILIDADES------------------------ UTILITIES
// Crear filtro para solo obtener los parametros requeridos, Filter to get the parameters requiered
StaticJsonDocument<200> getFilter() {
  StaticJsonDocument<200> filter;

  // Colocar "true" para la informacion requerida , Set true for the requiered info
  filter["is_playing"] = true;
  filter["device"]["volume_percent"] = true;
  filter["item"]["name"] = true;
  filter["item"]["album"]["artists"] = true;
  filter["item"]["duration_ms"] = true;
  filter["progress_ms"] = true;

  return filter;
}

// Imprime la cancion actual en el Serial , Prints the current song
void printCurrentSong() {
  Serial.print("Reproduciendo ahora: ");
  Serial.print(song_name);
  Serial.print(" de ");
  Serial.println(artist_name);
}

// Regresa el estilo de etiqueta HTML, Returns the style HTML tag
const char* getStyle() {
  return "<style>html{height:100\%;display:grid;justify-content:center;align-content:center;"
         "background-color:#1ED760;font-size:60px;}</style>";
}

String getHTML(const char* message) {
  String html = "<!DOCTYPE html>\n";
  html += "<html><body>";
  html += getStyle();
  html += "<div>";
  html += message;
  html += "</div></body></html>";
  return html;
}

// Regresa el indice del ultimo espacio antes del limite, Returns the last space index
int lastSpaceBeforeThreshold(String text, int threshold) {
  int prevIndex = 0;
  int index = text.indexOf(' ');
  while (index >= 0 && index < threshold) {
    prevIndex = index;
    index = text.indexOf(' ', index + 1);
  }
  return prevIndex;
}

//Regresa "true" si el indice de bit es 1, Returns true if the index bit is 1
bool isButtonPressed(byte states, byte index) {
  return (states & (1 << index)) > 0;
}

//--------------------------------AUTORIZACION-------------------AUTORIZATION
//Obtener el token de autorizacion del usuario, get the authorization user's token
bool getAccessToken(String userCode) {
  String postData = "grant_type=authorization_code&code=" + userCode + "&redirect_uri="
                    "http://" + ip_address + "/redirect/";
  authClient.beginRequest();
  authClient.post("/api/token");
  authClient.sendHeader("Content-Type", "application/x-www-form-urlencoded");
  authClient.sendHeader("Content-Length", postData.length());
  authClient.sendBasicAuth(SPOTIFY_CLIENT, SPOTIFY_SECRET); // Envia las credenciales de Spotify, Send Spotify's credentials
  authClient.beginBody();
  authClient.print(postData);
  authClient.endRequest();

  // Si fue exitoso , If succesful 
  if (authClient.responseStatusCode() == 200) {
    lastTokenTime = millis();
    DynamicJsonDocument json(512);
    deserializeJson(json, authClient.responseBody());
    accessToken = json["access_token"].as<String>();
    refreshToken = json["refresh_token"].as<String>();
    return true;
  }
  return false;
}

// Actualiza el token de autorizacion del usuario , Update the token
void refreshAccessToken() {
  String postData = "grant_type=refresh_token&refresh_token=" + refreshToken;
  authClient.beginRequest();
  authClient.post("/api/token");
  authClient.sendHeader("Content-Type", "application/x-www-form-urlencoded");
  authClient.sendHeader("Content-Length", postData.length());
  authClient.sendBasicAuth(SPOTIFY_CLIENT, SPOTIFY_SECRET); // Envia las credenciales de Spotify, Send Spotify's credentials
  authClient.beginBody();
  authClient.print(postData);
  authClient.endRequest();

  // Si fue exitoso, If succesful
  if (authClient.responseStatusCode() == 200) {
    lastTokenTime = millis();
    DynamicJsonDocument json(256);
    deserializeJson(json, authClient.responseBody());
    accessToken = json["access_token"].as<String>();
  }
}

//----------------------------------PETICION API-------------------------API REQUEST
//Obtener el estado actual del reproductor, Get the status of the player
void getPlayerState() {
  apiClient.beginRequest();
  apiClient.get("/v1/me/player");
  apiClient.sendHeader("Authorization", "Bearer " + accessToken);
  apiClient.endRequest();

  int statusCode = apiClient.responseStatusCode();
  // Si fue exitoso y esta reproduciendo (se debe de obtener el codigo de estado 204), If sucessful ans it is playing (status code 204)
  if (statusCode == 200) {
    // Crea un filtro ya que la respuesta es muy prolongada para que el Arduino lo soporte, Creta a filter to the Arduino be able to handle it
    StaticJsonDocument<200> filter = getFilter();
    DynamicJsonDocument json(4096);
    deserializeJson(json, apiClient.responseBody(), DeserializationOption::Filter(filter));
    is_playing = json["is_playing"].as<bool>();
    volume_percent = json["device"]["volume_percent"].as<int>();
    // Si la cancion a cambiado, If the song changes
    if (song_name != json["item"]["name"].as<String>()) {
      songProgress = json["progress_ms"].as<int>();
    }
    song_name = json["item"]["name"].as<String>();
    artist_name = json["item"]["album"]["artists"][0]["name"].as<String>();
    song_length = json["item"]["duration_ms"].as<int>();
    is_active = true;
    printCurrentSong();
  } else {
    is_active = false;
    is_playing = false;
  }
  updatePlayerDisplay();
}

//Saltar cancion en una direccion dada //Change song in a given direction
void skipSong(String direction) {
  apiClient.beginRequest();
  apiClient.post("/v1/me/player/" + direction);
  apiClient.sendHeader("Content-Length", 0);
  apiClient.sendHeader("Authorization", "Bearer " + accessToken);
  apiClient.endRequest();
}

//Saltar a la cancion anterior, Previous Song
void previousSong() {
  skipSong("previous");
  getPlayerState();
}

//Saltar a la cancion siguiente, Next Song
void nextSong() {
  skipSong("next");
  getPlayerState();
}

//Volumen del reproductor, Volume
void setVolume(int newVolume) {
  apiClient.beginRequest();
  apiClient.put("/v1/me/player/volume?volume_percent=" + String(newVolume));
  apiClient.sendHeader("Content-Length", 0);
  apiClient.sendHeader("Authorization", "Bearer " + accessToken);
  apiClient.endRequest();
}

// Subir volumen en un 5 pociento, Turn up the volume in 5%
/*void volumeUp() {
  int newVolume = volume_percent > 95 ? 100 : volume_percent + 5;
  setVolume(newVolume);
  getPlayerState();
}*/

//Bajar Volumen en un 10 porciento, Turn down the volume in 10%
void volumeDown() {
  int newVolume = volume_percent < 5 ? 0 : volume_percent - 10;
  setVolume(newVolume);
  getPlayerState();
}

//Cambio entre play/pause, Play/Pause
void playPause() {
  apiClient.beginRequest();
  apiClient.put("/v1/me/player/" + String(is_playing ? "pause" : "play"));
  apiClient.sendHeader("Content-Length", 0);
  apiClient.sendHeader("Authorization", "Bearer " + accessToken);
  apiClient.endRequest();
  getPlayerState();
}

//----------------------------------CONTROL DE LEDS--------------------------------- LED CONTROL
//Encender todos los LEDs en verde, Turn the LEDs in a green color
void flashLEDs() {
  for (int i = 0; i < 2; i++) {
    carrier.leds.setPixelColor(0, 0, 128, 0);
    carrier.leds.setPixelColor(1, 0, 128, 0);
    carrier.leds.setPixelColor(2, 0, 128, 0);
    carrier.leds.setPixelColor(3, 0, 128, 0);
    carrier.leds.setPixelColor(4, 0, 128, 0);
    carrier.leds.show();
    delay(100);
    turnOffLEDs();
    delay(100);
  }
}

//Ciclo de LEDs, LED's cycle
void cycleLEDs() {
  carrier.leds.setPixelColor(0, 0, 128, 0);
  carrier.leds.show();
  delay(20);
  carrier.leds.setPixelColor(0, 0);
  carrier.leds.setPixelColor(1, 0, 128, 0);
  carrier.leds.show();
  delay(20);
  carrier.leds.setPixelColor(1, 0);
  carrier.leds.setPixelColor(2, 128, 0, 0);
  carrier.leds.show();
  delay(20);
  carrier.leds.setPixelColor(2, 0);
  carrier.leds.setPixelColor(3, 0, 128, 0);
  carrier.leds.show();
  delay(20);
  carrier.leds.setPixelColor(3, 0);
  carrier.leds.setPixelColor(4, 0, 128, 0);
  carrier.leds.show();
  delay(20);
  carrier.leds.setPixelColor(4, 0);
  carrier.leds.show();
}

//Apagar todos los LEDs, Turn off the LEDs
void turnOffLEDs() {
  carrier.leds.setPixelColor(0, 0);
  carrier.leds.setPixelColor(1, 0);
  carrier.leds.setPixelColor(2, 0);
  carrier.leds.setPixelColor(3, 0);
  carrier.leds.setPixelColor(4, 0);
  carrier.leds.show();
}

//------------------------------CONTROL DE BOTONES------------------- BUTTONS CONROL
//Obetener el estado de todos los botones al mismo tiempo, Get the status of all the buttons at once
byte getButtonStates() {
  byte states = 0;
  states |= carrier.Buttons.onTouchDown(TOUCH0) << 0;
  states |= carrier.Buttons.onTouchDown(TOUCH1) << 1;
  states |= carrier.Buttons.onTouchDown(TOUCH2) << 2;
  /*states |= carrier.Buttons.onTouchDown(TOUCH3) << 3;*/ //No funciona bien este boton, this buttons didnt work well for us!
  states |= carrier.Buttons.onTouchDown(TOUCH4) << 4;
  return states;
}

// Checar el estadode los botones y actuar de forma adecuada, Chek the buttons statu
void checkButtonStates() {
  carrier.Buttons.update();
  byte states = getButtonStates();

  if (!authenticated) {
    if (states > 0) {
      flashLEDs();
    }
  } else if (!is_active) {
    if (states > 0) {
      cycleLEDs();
      getPlayerState();      
    }
  } else {
    // Button 0 - Bajar Volumen, Tunr down volume
    if (isButtonPressed(states, 0)) {
      carrier.leds.setPixelColor(0, 128, 0, 0);
      carrier.leds.show();
      volumeDown();
      carrier.leds.setPixelColor(0, 0);
      carrier.leds.show();
      return;
    }

    // Button 1 - Cancion previa, Previous song
    if (isButtonPressed(states, 1)) {
      carrier.leds.setPixelColor(1, 128, 0, 0);
      carrier.leds.show();
      previousSong();
      carrier.leds.setPixelColor(1, 0);
      carrier.leds.show();
      return;
    }

    // Button 2 - Play/Pause,
    if (isButtonPressed(states, 2)) {
      carrier.leds.setPixelColor(2, 128, 0, 0);
      carrier.leds.show();
      playPause();
      carrier.leds.setPixelColor(2, 0);
      carrier.leds.show();
      return;
    }

    // Button 3 - Subir Volumen, Turn Up volume
    /*if (isButtonPressed(states, 3)) {
      carrier.leds.setPixelColor(3, 128, 0, 0);
      carrier.leds.show();
      volumeUp();
      carrier.leds.setPixelColor(3, 0);
      carrier.leds.show();
      return;
    }*/

    // Button 4 - Canccion siguiente, Next Song
    if (isButtonPressed(states, 4)) {
      carrier.leds.setPixelColor(4, 128, 0, 0);
      carrier.leds.show();
      nextSong();
      carrier.leds.setPixelColor(4, 0);
      carrier.leds.show();
      return;
    }
  }
}

//----------------------------CONTROL DE DISPLAY-------------------- DISPLAY CONTROL
//Imprimir iconos de reproductor, Print player icons
void printMediaIcons() {
  // Regresar cancion, Previous song
  carrier.display.fillTriangle(38, 51, 51, 43, 51, 59, ST77XX_WHITE);
  carrier.display.fillTriangle(51, 51, 64, 43, 64, 59, ST77XX_WHITE);

  // Saltar cancion, Next song
  carrier.display.fillTriangle(189, 154, 189, 170, 202, 162, ST77XX_WHITE);
  carrier.display.fillTriangle(202, 154, 202, 170, 215, 162, ST77XX_WHITE);

  // Subir volumen, Turn up volume
  //carrier.display.fillRect(203, 43, 8, 24, ST77XX_WHITE);
  //carrier.display.fillRect(195, 8, 24, 8, ST77XX_WHITE);
  carrier.display.setTextColor(ST77XX_WHITE);
  carrier.display.setTextSize(1); // 6 x 8
  carrier.display.setCursor(170, 51);
  carrier.display.print("No Sirvo"); //I dont work in spanish lol
  carrier.display.setTextWrap(true);
  

  // Bajar volumen, Turn Down volume
  carrier.display.fillRect(21, 162, 24, 8, ST77XX_WHITE);

  // Play/Pause
  printPlayPause();
}

//Imprimir el logo, Print logo
void printLogo() {
  carrier.display.drawBitmap(60, 60, LOGO, 120, 120, 0x26CC);
}

//Inicializar el display, Starts the display
void initializePlayerDisplay() {
  carrier.display.fillScreen(ST77XX_BLACK);
  printLogo();
  printMediaIcons();
}

//Dibujar el icono de play o pausa dependiendo si esta reproduciendo, Draw the play/pause icon depending on the status
void printPlayPause() {
  if (lastDrawnState == (is_playing ? Pause : Play)) {
    return;
  }

  // Primero borrar el display, Erase the display
  carrier.display.fillRect(105, 1, 30, 30, ST77XX_BLACK);

  // Ahora, dibuja el icono correspondiente, Draw the correct icon 
  if (is_playing) {
    // Pause icono, Pause
    carrier.display.fillRect(113, 6, 5, 23, ST77XX_WHITE);
    carrier.display.fillRect(122, 6, 5, 23, ST77XX_WHITE);
  } else {
    // Play icono, Play
    carrier.display.fillTriangle(112, 4, 112, 26, 128, 15, ST77XX_WHITE);
  }
  lastDrawnState = is_playing ? Pause : Play;
}

//Extiende la barra de progreso si la cancion se esta reproduciendo, ademas la elimina, Extend the progress bar if the song is playing
void updateTrackBar() {
  if (is_playing) {
    songProgress += millis() - lastTrackTime;
    if (songProgress > song_length) {
      getPlayerState();
      return;
    }
    carrier.display.drawRect(80, 220, 80, 5, ST77XX_GREEN); // Dibuja el contorno de la barra de progreso, Draw the outline of the progress bar
    int progress = 78 * songProgress / song_length;
    carrier.display.fillRect(81, 221, progress, 3, ST77XX_WHITE); // Dibuja la barra de progreso, Draw the progress bar
    carrier.display.fillRect(81 + progress, 221, 76 - progress, 3, ST77XX_BLACK); // Dibuja la barra que en negro (la parte que aun no esta en progreo), Draw the progress bar of the unplayed part of the song
  } else {
    carrier.display.fillRect(80, 220, 80, 5, ST77XX_BLACK); // Elimina la barra de progreso, Erase the progress bar
  }
  lastTrackTime = millis();
}

//Actualiza el nombre de la cancion si la cancion se esta reproduciendo, si no la elimina, Update the name of the song if is playing
void updateTrackName() {
  carrier.display.fillRect(70, 186, 100, 33, ST77XX_BLACK); // Elimina el nombre de la cancion, Erase the song name
  if (is_playing) {
    // Imprime el nombre de la cancion, Print the song name
    carrier.display.setTextColor(ST77XX_WHITE);
    carrier.display.setTextSize(1); // 6 x 8
    carrier.display.setCursor(70, 186);
    if (song_name.length() > 16) {
      // Intenta no partir palabras a la mitad, Try to no break words
      int lastSpace = lastSpaceBeforeThreshold(song_name, 16);
      if (lastSpace > 0) {
        carrier.display.print(song_name.substring(0, lastSpace));
        carrier.display.setCursor(70, 194);
        carrier.display.print(song_name.substring(lastSpace + 1, song_name.length() > lastSpace + 17 ?
                              lastSpace + 17 : song_name.length()));
      } else {
        carrier.display.print(song_name.substring(0, 16));
        carrier.display.setCursor(70, 194);
        carrier.display.print(song_name.substring(16, song_name.length() > 32 ? 32 : song_name.length()));
      }
    } else {
      carrier.display.print(song_name);
    }

    // Imprime el nombre del artista, Print the artist name
    carrier.display.setTextColor(0xCE59); // Gris, Gray
    carrier.display.setTextSize(1); // 6 x 8
    carrier.display.setCursor(70, 209);
    carrier.display.print(artist_name.substring(0, artist_name.length() > 16 ? 16 : artist_name.length()));
  }
}

//Actualiza el estado del reproductor, Update the status of the player
void updatePlayerDisplay() {
  printPlayPause();
  updateTrackBar();
  updateTrackName();
}

//Imprime el mensaje de autenticacion, Print the authentication message
void printAuthMessage() {
  carrier.display.fillScreen(ST77XX_BLACK);
  carrier.display.setTextColor(ST77XX_WHITE);
  carrier.display.setTextSize(2); // 12 x 16

  carrier.display.setCursor(80, 92);
  carrier.display.print("Porfavor"); 
  //carrier.display.print("Please");

  carrier.display.setCursor(30, 110);
  carrier.display.print("autentica en"); 
  //carrier.display.print("Authenticate in");


  carrier.display.setCursor(30 + (22 - ip_address.length()) / 2, 128);
  carrier.display.print(ip_address);
}

//-------------------------EVENTOS--------------------- EVENTS
//Actualiza la direccion IP cuando se conecta, Update the IP address when is connected
void onNetworkConnect() {
  IPAddress ip = WiFi.localIP();
  ip_address = String(ip[0]) + "." + String(ip[1]) + "." + String(ip[2]) + "." + String(ip[3]);
  printAuthMessage();
  Serial.println("Please authenticate at " + ip_address);
}

//-----------------------------------SETUP Y LOOP-----------------------
void setup() {
  Serial.begin(9600);

  //Inicializar las variables // initialize the variables
  volume_percent = 0;
  song_length = 0;
  is_active = false;
  is_playing = false;
  song_name = "";
  artist_name = "";
  carrier.Buzzer.beep();
  delay(400);
  carrier.Buzzer.noSound();
  // Definido en thingProperties.h, Defined in thingProperties.h
  initProperties();

  // Conectar a Arduino IoT Cloud //Connect to Ardino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection, false); // disable watchdog restart

  // Anadir una coneccion de llamada, Add a callback connection
  ArduinoIoTPreferredConnection.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);

  //Inicializar el carrier, Initialize the carrier
  CARRIER_CASE = true; 
  carrier.begin();
  carrier.display.setRotation(0);
  
  /*//Iteracion de las notas de la melodia, Iteration of the notes of the melody
   for (int thisNote = 0; thisNote < 8; thisNote++) {
    //Para calcular la duracion de las notas, toma 1 segundo dividido por el tipo de nota. To calculate the duration of the notes, take 1 second divided by the type of note
    //Ejemplo: Cuarto de nota = 1000/4, etc.
    int noteDuration = 1000 / noteDurations[thisNote];
    carrier.Buzzer.sound(melody[thisNote]);
    delay(noteDuration);
    // Para distinguir las notas, configura un minimo de tiempo entre ellos.To distinguish the notes, set a minimum time between them
    // la duracion de las notas + 50% trabaja bien. Note duration + 50% works fine
    int pauseBetweenNotes = noteDuration * 1.50;
    delay(pauseBetweenNotes);
    // Detener los sonidos, stop the sound
    carrier.Buzzer.noSound();
  }*/
  //Iniciar el server, Initialize the server
  server.begin();
  
   //NeoPixel
  pixels.begin();  // Inicializa la barra de NeoPixel, Initalize the NeoPixel Strip
  //COLOR
  pixels.clear();  // Apaga todos los LEDs, Turn off the leds
  
  //Prende en colores la barra, turn on the strip with colors
  for (int i = 0; i < 59; i++) {  // Para cada LED... For each LED...
    pixels.setPixelColor(i, pixels.Color(0, 255, 100));
    pixels.show();  
    delay(DELAYVAL);
  }
  // Segunda hilera de LEDs, Second LEDs row
  for (int i = 60; i < 118; i++) { 
    pixels.setPixelColor(i, pixels.Color(255, 0, 255));
    pixels.show(); 
    delay(DELAYVAL);  
  }
}

void loop() {
  ArduinoCloud.update();
  checkButtonStates();

  if (!authenticated) {
    // Esperar a que el usuario se conecte, Wait to the user to connect
    WiFiClient wifiClient = server.available();

    // Si el usuario se ha conectado, If the user has connected
    if (wifiClient) {
      // Obtener la peticion, Get the request
      String header = "";
      while (wifiClient.available()) {
        header += char(wifiClient.read());
      }

      // Si esta autenticado, redirigir, If authenticated, redirect
      if (header.indexOf("?code") >= 0) {
        // Analizar el token, Analize the token
        String userCode = header.substring(header.indexOf("code=") + 5, header.indexOf("HTTP/1.1") - 1);
        authenticated = getAccessToken(userCode);
        if (authenticated) {
          wifiClient.print(getHTML("Authenticated!"));
          initializePlayerDisplay();
          getPlayerState();
        } else {
          wifiClient.print(getHTML("Authentication failed."));
        }
      } else if (header.indexOf("?error") >= 0) {
        wifiClient.print(getHTML("Cancelled."));
      }
      else {
        // Autenticar el usuario y el token, Authenticate the user and the token
        String webpage = "<!DOCTYPE html>\n";
        webpage += "<html><body>";
        webpage += getStyle();
        webpage += "<a href=\"https://accounts.spotify.com/authorize?client_id=";
        webpage += SPOTIFY_CLIENT;
        webpage += "&response_type=code&redirect_uri=http://";
        webpage += ip_address;
        webpage += "/redirect/&scope=user-read-playback-state "
                   "user-modify-playback-state\">Authenticate Spotify</a>\n";
        webpage += "</body></html>";
        wifiClient.print(webpage);
      }
      wifiClient.stop();
    }
  } else if (millis() - lastTokenTime > TOKEN_REFRESH_RATE) {
    // Refrescar token si esta a punto de expirar, Refresh the token if is about to expire
    refreshAccessToken();
  } else if (millis() - lastTrackTime > UPDATE_REFRESH_RATE) {
    // Actualzar la barra de progreso, Update the progress bar
    updateTrackBar();
  }
}

arduino_secrets.h

C/C++
Arduino Secret File to save the credentials
#define SECRET_SPOTIFY_CLIENT ""
#define SECRET_SPOTIFY_SECRET ""
#define SECRET_SSID ""
#define SECRET_PASS ""

thingProperties.h

Arduino
// Code generated by Arduino IoT Cloud, DO NOT EDIT.

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

const char SSID[]     = SECRET_SSID;    // Network SSID (name)
const char PASS[]     = SECRET_PASS;    // Network password (use for WPA, or use as key for WEP)


String artist_name;
String ip_address;
String song_name;
int song_length;
int volume_percent;
bool is_active;
bool is_playing;

void initProperties(){

  ArduinoCloud.addProperty(artist_name, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(ip_address, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(song_name, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(song_length, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(volume_percent, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(is_active, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(is_playing, READ, ON_CHANGE, NULL);

}

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);

Logo.h

C/C++
Logo in C file
// Logo, https://github.com/bitbank2/image_to_c
const unsigned char LOGO[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
	0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 
	0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x80, 
	0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x00, 
	0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 
	0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 
	0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 
	0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 
	0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
	0xff, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 
	0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc, 
	0x00, 0x7e, 0x00, 0x3f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x3f, 
	0xff, 0xfc, 0x3f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe1, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0x87, 0xff, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 
	0xf8, 0x03, 0xff, 0x80, 0x03, 0xe0, 0x07, 0xe0, 0x01, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xc0, 
	0x03, 0xff, 0x80, 0x07, 0xf0, 0x0e, 0x60, 0x03, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x03, 
	0xff, 0xc0, 0x06, 0x70, 0x0c, 0x70, 0x03, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x03, 0xff, 
	0xc0, 0x0e, 0x30, 0x0e, 0x7c, 0x03, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xc0, 
	0x3e, 0x30, 0x0f, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xc0, 0xff, 
	0xf0, 0x07, 0xff, 0xc7, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xe3, 0xff, 0xe0, 
	0x01, 0x0f, 0xf7, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xef, 0xf0, 0x80, 0x00, 
	0x03, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 
	0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 
	0xff, 0xf0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 
	0xf0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xf8, 
	0x00, 0x07, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 
	0x07, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x3c, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07, 
	0xff, 0xe0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3c, 0x7e, 0x00, 0x07, 0xff, 0xff, 0x00, 0x07, 0xff, 
	0xe0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7e, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xe0, 
	0x03, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xe0, 0x1f, 
	0xff, 0xff, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe7, 0x7f, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0x80, 0x00, 0xfe, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
	0x00, 0x7e, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 
	0x18, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 
	0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 
	0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 
	0x7f, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xfe, 0x00, 0x00, 0x00, 0x01, 0xfe, 
	0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0x80, 0x00, 0x00, 0x07, 0xf8, 0x03, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xe0, 0x00, 0x03, 0xdf, 0xe0, 0x01, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xfb, 0xc0, 0x07, 0xff, 0x80, 0x00, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xe0, 0x0e, 0x7c, 0x00, 0x00, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3e, 0x70, 0x0c, 0x78, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xf8, 0x00, 0x00, 0x0e, 0x30, 0x0c, 0x70, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xe0, 0x00, 0x00, 0x06, 0x30, 0x0f, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0x80, 0x00, 0x00, 0x07, 0xf0, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x00, 
	0x00, 0x00, 0x07, 0xe0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 
	0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

pitches.h

C/C++
Needed to play buzzer melodies
/*************************************************
 * Public Constants
 *************************************************/
#define REST      0
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

Credits

Andres Sabas
48 projects • 47 followers
Co-Founder of The Inventor's House Hackerspace, DIY, Workaholic
Carlos Alatorre
17 projects • 5 followers
Mechatronic Engineer working on supporting you! An open source user. I'm very curious in almost most of my life areas. Born and raised in MX
Thanks to Altug.

Comments