Skip to content

Instantly share code, notes, and snippets.

@witnessmenow
Last active July 16, 2020 07:09
Show Gist options
  • Save witnessmenow/063dcd4b4407aa51afb4f6a0a442b5af to your computer and use it in GitHub Desktop.
Save witnessmenow/063dcd4b4407aa51afb4f6a0a442b5af to your computer and use it in GitHub Desktop.
Spotify TJpg POC - a demo of displaying album art on a matrix
/***************************************************************************************
** Function name: listSPIFFS
** Description: Listing SPIFFS files
***************************************************************************************/
#ifdef ESP8266
void listSPIFFS(void) {
Serial.println(F("\r\nListing SPIFFS files:"));
fs::Dir dir = SPIFFS.openDir("/"); // Root directory
static const char line[] PROGMEM = "=================================================";
Serial.println(FPSTR(line));
Serial.println(F(" File name Size"));
Serial.println(FPSTR(line));
while (dir.next()) {
String fileName = dir.fileName();
Serial.print(fileName);
int spaces = 33 - fileName.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
fs::File f = dir.openFile("r");
String fileSize = (String) f.size();
spaces = 10 - fileSize.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
Serial.println(fileSize + " bytes");
}
Serial.println(FPSTR(line));
Serial.println();
delay(1000);
}
//====================================================================================
#elif defined ESP32
void listSPIFFS(void) {
Serial.println(F("\r\nListing SPIFFS files:"));
static const char line[] PROGMEM = "=================================================";
Serial.println(FPSTR(line));
Serial.println(F(" File name Size"));
Serial.println(FPSTR(line));
fs::File root = SPIFFS.open("/");
if (!root) {
Serial.println(F("Failed to open directory"));
return;
}
if (!root.isDirectory()) {
Serial.println(F("Not a directory"));
return;
}
fs::File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print("DIR : ");
String fileName = file.name();
Serial.print(fileName);
} else {
String fileName = file.name();
Serial.print(" " + fileName);
// File path can be 31 characters maximum in SPIFFS
int spaces = 33 - fileName.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
String fileSize = (String) file.size();
spaces = 10 - fileSize.length(); // Tabulate nicely
if (spaces < 1) spaces = 1;
while (spaces--) Serial.print(" ");
Serial.println(fileSize + " bytes");
}
file = root.openNextFile();
}
Serial.println(FPSTR(line));
Serial.println();
delay(1000);
}
#endif
// Fetch a file from the URL given and save it in SPIFFS
// Return 1 if a web fetch was needed or 0 if file already exists
bool getFile(String url, String filename) {
// If it exists then no need to fetch it
if (SPIFFS.exists(filename) == true) {
Serial.println("Found " + filename);
return 0;
}
Serial.println("Downloading " + filename + " from " + url);
WiFiClientSecure *client = new WiFiClientSecure;
if (client) {
client -> setCACert(spotify_server_cert);
{
// Check WiFi connection
if ((WiFi.status() == WL_CONNECTED)) {
HTTPClient http;
Serial.print("[HTTP] begin...\n");
// Configure server and url
http.begin(*client, url);
Serial.print("[HTTP] GET...\n");
// Start connection and send HTTP header
int httpCode = http.GET();
if (httpCode > 0) {
fs::File f = SPIFFS.open(filename, "w+");
if (!f) {
Serial.println("file open failed");
return 0;
}
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// File found at server
if (httpCode == HTTP_CODE_OK) {
// Get length of document (is -1 when Server sends no Content-Length header)
int total = http.getSize();
int len = total;
// Create buffer for read
uint8_t buff[128] = { 0 };
// Get tcp stream
WiFiClient * stream = http.getStreamPtr();
// Read all data from server
while (http.connected() && (len > 0 || len == -1)) {
// Get available data size
size_t size = stream->available();
if (size) {
// Read up to 128 bytes
int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
// Write it to file
f.write(buff, c);
// Calculate remaining bytes
if (len > 0) {
len -= c;
}
}
yield();
}
Serial.println();
Serial.print("[HTTP] connection closed or file end.\n");
}
f.close();
}
else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
}
delete client;
} else {
Serial.println("Unable to create client");
return -1;
}
return 1; // File was fetched from web
}
/*******************************************************************
Display an image from Spotify on a matrix display
This is a rough proof of concept
This is a mashup of two examples from the TJpg_Decoder library,
further modified to add support for HTTPS
Parts:
ESP32 D1 Mini * - https://s.click.aliexpress.com/e/_dSi824B
ESP32 I2S Matrix Shield (From my Tindie) = https://www.tindie.com/products/brianlough/esp32-i2s-matrix-shield/
* * = Affilate
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
*******************************************************************/
// Example for library:
// https://github.com/Bodmer/TJpg_Decoder
// This example is for an ESP8266 or ESP32, it fetches a Jpeg file
// from the web and saves it in a SPIFFS file. You must have SPIFFS
// space allocated in the IDE.
// Chenge next 2 lines to suit your WiFi network
#define WIFI_SSID "wifi"
#define PASSWORD "pass"
#define ALBUM_ART "/album.jpg"
// Include the jpeg decoder library
#include <TJpg_Decoder.h>
// https://github.com/Bodmer/TJpg_Decoder
// Include SPIFFS
#define FS_NO_GLOBALS
#include <FS.h>
// Include WiFi and http client
#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#else
#include "SPIFFS.h" // Required for ESP32 only
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#endif
#include <ArduinoSpotifyCert.h>
// Load tabs attached to this sketch
#include "List_SPIFFS.h"
#include "Web_Fetch.h"
#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>
RGB64x32MatrixPanel_I2S_DMA dma_display;
// This next function will be called during decoding of the jpeg file to
// render each block to the TFT. If you use a different TFT library
// you will need to adapt this function to suit.
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= dma_display.height() ) return 0;
dma_display.drawRGBBitmap(x, y, bitmap, w, h);
// Return 1 to decode next block
return 1;
}
void setup()
{
Serial.begin(115200);
Serial.println("\n\n Testing TJpg_Decoder library");
// Initialise SPIFFS
if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS initialisation failed!");
while (1) yield(); // Stay here twiddling thumbs waiting
}
Serial.println("\r\nInitialisation done.");
// Initialise the TFT
dma_display.begin();
dma_display.fillScreen(dma_display.color565(0, 0, 0));
// The jpeg image can be scaled by a factor of 1, 2, 4, or 8
TJpgDec.setJpgScale(1);
// The decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
// The byte order can be swapped (set true for TFT_eSPI)
//TJpgDec.setSwapBytes(true);
WiFi.begin(WIFI_SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
// This is for demoe purposes only so that file is fetched each time this is run
if (SPIFFS.exists(ALBUM_ART) == true) {
Serial.println("For test only, removing file");
SPIFFS.remove(ALBUM_ART);
//SPIFSS.remove("/F35.jpg");
}
}
void loop()
{
// List files stored in SPIFFS
listSPIFFS();
// Time recorded for test purposes
uint32_t t = millis();
// Fetch the jpg file from the specified URL, examples only, from imgur
bool loaded_ok = getFile("https://i.scdn.co/image/ab67616d00004851d72fb5571087bca0a2fed008", ALBUM_ART); // Note name preceded with "/"
//bool loaded_ok = downloadFile("http://i.imgur.com/OnW2qOO.jpg", "/F35.jpg");
t = millis() - t;
if (loaded_ok) { Serial.print(t); Serial.println(" ms to download"); }
// List files stored in SPIFFS, should have the file now
listSPIFFS();
t = millis();
// Now draw the SPIFFS file
TJpgDec.drawFsJpg(0, 0, ALBUM_ART);
//TJpgDec.drawFsJpg(0, 0, "/F35.jpg");
t = millis() - t;
Serial.print(t); Serial.println(" ms to draw to TFT");
// Wait forever
while(1) yield();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment