#include #include #include #include #include #include #include const char* ssid = "WIFI_SSID"; const char* password = "WIFI_SSID_PASSWORD"; byte lastUid[10]; // large enough for UID byte lastUidSize = 0; const char* CLIENT_ID = "YOUR_CLIENT_ID"; const char* CLIENT_SECRET = "YOUR_CLIENT_SECRET"; const char* REFRESH_TOKEN = "YOUR_REFRESH_TOKEN"; #define RST_PIN 13 #define SS_PIN 5 #define motor 27 MFRC522 mfrc522(SS_PIN, RST_PIN); Spotify sp(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN); WebServer server(80); String receivedUri = ""; // <- store latest URI bool writePending = false; // <- flag to indicate pending write void setup() { pinMode(motor, OUTPUT); Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); connect_to_wifi(); server.on("/uri", HTTP_POST, handleUriPost); server.on("/play", HTTP_POST, handlePlay); server.on("/pause", HTTP_POST, handlePause); server.on("/prev", HTTP_POST, handlePrev); server.on("/next", HTTP_POST, handleNext); server.begin(); Serial.println("HTTP server started"); sp.begin(); while (!sp.is_auth()) { sp.handle_client(); } Serial.println("Authenticated"); } void loop() { server.handleClient(); read_nfc(); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); delay(3000); } void connect_to_wifi() { WiFi.begin(ssid, password); Serial.print("Connecting to WiFi..."); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); } Serial.printf("\nConnected to WiFi\n"); Serial.println(WiFi.localIP()); } void handleUriPost() { if (server.hasArg("uri")) { receivedUri = server.arg("uri"); Serial.println("Received URI: " + receivedUri); while (writePending) { write_nfc(); } bool writeSuccess = write_nfc(); // call directly if (writeSuccess) { server.send(200, "text/plain", "NFC card written successfully!"); } else { server.send(500, "text/plain", "Failed to write NFC card. Please try again."); } } else { server.send(400, "text/plain", "Missing 'uri' parameter"); } } void handlePlay() { Serial.println("Received Toggle Play/Pause Command"); sp.start_resume_playback(); analogWrite(motor, 30); server.send(200, "text/plain", "Playing Track"); } void handlePause() { Serial.println("Received Pause Command"); sp.pause_playback(); analogWrite(motor, 0); server.send(200, "text/plain", "Paused Track"); } void handlePrev() { Serial.println("Received Previous Command"); sp.previous(); server.send(200, "text/plain", "Played Previous Track"); } void handleNext() { Serial.println("Received Next Command"); sp.skip(); server.send(200, "text/plain", "Played Next Track"); } bool write_nfc() { // memset(lastUid, 0, sizeof(lastUid)); // lastUidSize = 0; // Serial.println("Waiting for NFC card to write..."); MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // Default key // if (!mfrc522.PICC_IsNewCardPresent()) return; // if (!mfrc522.PICC_ReadCardSerial()) return; if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) { Serial.println("No new card detected."); return false; } Serial.println(); // Prepare data byte buffer1[16]; byte buffer2[16]; const char* playlistID = receivedUri.c_str(); size_t len = strlen(playlistID); // Fill buffer1 with first 16 bytes for (byte i = 0; i < 16; i++) { buffer1[i] = (i < len) ? playlistID[i] : ' '; } // Fill buffer2 with next 16 bytes (if any) for (byte i = 0; i < 16; i++) { byte index = i + 16; buffer2[i] = (index < len) ? playlistID[index] : ' '; } // Write to block 1 byte block = 1; MFRC522::StatusCode status; status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("Auth failed for block 1: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } status = mfrc522.MIFARE_Write(block, buffer1, 16); if (status != MFRC522::STATUS_OK) { Serial.print(F("Write failed for block 1: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } Serial.println(F("Block 1 written successfully.")); // Write to block 2 block = 2; status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("Auth failed for block 2: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } status = mfrc522.MIFARE_Write(block, buffer2, 16); if (status != MFRC522::STATUS_OK) { Serial.print(F("Write failed for block 2: ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } Serial.println(F("Block 2 written successfully.")); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); delay(100); mfrc522.PCD_Init(); memset(lastUid, 0, sizeof(lastUid)); lastUidSize = 0; Serial.println(F("Done writing Spotify ID!")); writePending = false; // clear the flag after writing return true; } void read_nfc() { // memset(lastUid, 0, sizeof(lastUid)); // lastUidSize = 0; MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // Default key if (!mfrc522.PICC_IsNewCardPresent()) return; if (!mfrc522.PICC_ReadCardSerial()) return; // Compare with last UID bool sameCard = (mfrc522.uid.size == lastUidSize); for (byte i = 0; i < mfrc522.uid.size && sameCard; i++) { if (mfrc522.uid.uidByte[i] != lastUid[i]) { sameCard = false; } } if (sameCard) { Serial.println("Same card detected again. Ignoring."); return; } // Store new UID memcpy(lastUid, mfrc522.uid.uidByte, mfrc522.uid.size); lastUidSize = mfrc522.uid.size; Serial.print(F("Card UID: ")); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); byte buffer1[18]; // 16 bytes + 2 for CRC byte size = sizeof(buffer1); byte block; // Read block 1 block = 1; if (!authenticateAndRead(block, buffer1, size, key)) return; // Read block 2 block = 2; byte buffer2[18]; size = sizeof(buffer2); if (!authenticateAndRead(block, buffer2, size, key)) return; // Combine both buffers into one string char context_uri[64]; // 32 + null terminator for (int i = 0; i < 16; i++) { context_uri[i] = (char)buffer1[i]; context_uri[i + 16] = (char)buffer2[i]; } context_uri[32] = '\0'; // null terminator // Trim trailing spaces for (int i = 31; i >= 0; i--) { if (context_uri[i] == ' ') { context_uri[i] = '\0'; } else { break; } } char final_uri[80]; snprintf(final_uri, sizeof(final_uri), "spotify:%s", context_uri); //concatenating 'spotify:playlist:'+'context_uri' into 'final_uri' Serial.print(F("Context URI: ")); Serial.println(final_uri); response resp = sp.start_resume_playback(final_uri, 0, 0, nullptr); //send the put message to play the final_uri if (resp.status_code == 204 || resp.status_code == 200) { Serial.println(F("Playback started successfully!")); analogWrite(motor, 30); } else { Serial.print(F("Failed to start playback. HTTP code: ")); Serial.println(resp.status_code); } // Serial.print(F("Playlist ID: ")); // Serial.println(context_uri); } bool authenticateAndRead(byte block, byte* buffer, byte& size, MFRC522::MIFARE_Key& key) { MFRC522::StatusCode status; status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print(F("Authentication failed for block ")); Serial.print(block); Serial.print(F(": ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } status = mfrc522.MIFARE_Read(block, buffer, &size); if (status != MFRC522::STATUS_OK) { Serial.print(F("Read failed for block ")); Serial.print(block); Serial.print(F(": ")); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } return true; }