ids, resume function
This commit is contained in:
parent
578281d9d1
commit
9c4b1d4913
|
|
@ -1,7 +1,11 @@
|
|||
#include "DirectoryNode.h"
|
||||
|
||||
|
||||
DirectoryNode::DirectoryNode(const String &nodeName)
|
||||
: name(nodeName), currentPlaying(nullptr) {}
|
||||
: name(nodeName), currentPlaying(nullptr) {
|
||||
id = DirectoryNode::idCounter;
|
||||
DirectoryNode::idCounter++;
|
||||
}
|
||||
|
||||
DirectoryNode::~DirectoryNode()
|
||||
{
|
||||
|
|
@ -11,6 +15,12 @@ DirectoryNode::~DirectoryNode()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
const uint16_t DirectoryNode::getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const String &DirectoryNode::getName() const
|
||||
{
|
||||
return name;
|
||||
|
|
@ -29,6 +39,11 @@ const std::vector<String> &DirectoryNode::getMP3Files() const
|
|||
void DirectoryNode::setCurrentPlaying(const String *mp3File)
|
||||
{
|
||||
currentPlaying = mp3File;
|
||||
for (int i=0;i<mp3Files.size();i++) {
|
||||
if (mp3Files[i] == *mp3File && ids.size()>i) {
|
||||
currentPlayingId = ids[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const String *DirectoryNode::getCurrentPlaying() const
|
||||
|
|
@ -36,6 +51,17 @@ const String *DirectoryNode::getCurrentPlaying() const
|
|||
return currentPlaying;
|
||||
}
|
||||
|
||||
const uint16_t DirectoryNode::getCurrentPlayingId() const
|
||||
{
|
||||
return currentPlayingId;
|
||||
}
|
||||
|
||||
uint16_t DirectoryNode::getNextId() {
|
||||
uint16_t next = DirectoryNode::idCounter;
|
||||
DirectoryNode::idCounter++;
|
||||
return next;
|
||||
}
|
||||
|
||||
void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory)
|
||||
{
|
||||
subdirectories.push_back(subdirectory);
|
||||
|
|
@ -44,6 +70,7 @@ void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory)
|
|||
void DirectoryNode::addMP3File(const String &mp3File)
|
||||
{
|
||||
mp3Files.push_back(mp3File);
|
||||
ids.push_back(getNextId());
|
||||
}
|
||||
|
||||
void DirectoryNode::setSecondsPlayed(const uint32_t seconds) {
|
||||
|
|
@ -65,7 +92,7 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
|
|||
break;
|
||||
}
|
||||
|
||||
if (entry.isDirectory() && strcmp(entry.name(),sys_dir.c_str()))
|
||||
if (entry.isDirectory() && entry.name()[0] != '.' && strcmp(entry.name(),sys_dir.c_str()))
|
||||
{
|
||||
DirectoryNode *newNode = new DirectoryNode(entry.name());
|
||||
subdirectories.push_back(newNode);
|
||||
|
|
@ -74,6 +101,7 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
|
|||
else if (String(entry.name()).endsWith(".mp3"))
|
||||
{
|
||||
mp3Files.push_back(entry.name());
|
||||
ids.push_back(getNextId());
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
|
|
@ -127,10 +155,43 @@ DirectoryNode *DirectoryNode::findFirstDirectoryWithMP3s()
|
|||
|
||||
void DirectoryNode::advanceToFirstMP3InThisNode() {
|
||||
if (mp3Files.size()>0) {
|
||||
currentPlaying = &mp3Files[0];
|
||||
setCurrentPlaying(&mp3Files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DirectoryNode* DirectoryNode::advanceToMP3(const uint16_t id) {
|
||||
for (auto subdir : subdirectories)
|
||||
{
|
||||
if (subdir->getId()==id) {
|
||||
subdir->advanceToFirstMP3InThisNode();
|
||||
return subdir;
|
||||
}
|
||||
|
||||
// Have each subdirectory advance its song
|
||||
for (size_t i = 0; i < subdir->ids.size(); i++)
|
||||
{
|
||||
if (id == subdir->ids[i])
|
||||
{
|
||||
// Found the current MP3 file
|
||||
if (i < subdir->mp3Files.size() - 1)
|
||||
{
|
||||
subdir->currentPlaying = &subdir->mp3Files[i];
|
||||
subdir->currentPlayingId = id;
|
||||
return subdir;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, there were no MP3 files or subdirectories left to check
|
||||
currentPlaying = nullptr;
|
||||
Serial.println("no more nodes found");
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) {
|
||||
for (auto subdir : subdirectories)
|
||||
{
|
||||
|
|
@ -147,7 +208,7 @@ DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) {
|
|||
// Found the current MP3 file
|
||||
if (i < subdir->mp3Files.size() - 1)
|
||||
{
|
||||
subdir->currentPlaying = &subdir->mp3Files[i];
|
||||
subdir->setCurrentPlaying(&subdir->mp3Files[i]);
|
||||
return subdir;
|
||||
}
|
||||
|
||||
|
|
@ -169,13 +230,13 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
|
|||
{
|
||||
for (size_t i = 0; i < mp3Files.size(); i++)
|
||||
{
|
||||
if (*currentGlobal == mp3Files[i])
|
||||
if (*currentGlobal==mp3Files[i])
|
||||
{
|
||||
// Found the current playing MP3 file
|
||||
if (i < mp3Files.size() - 1)
|
||||
{
|
||||
// Advance to the next MP3 file in the same directory
|
||||
currentPlaying = &mp3Files[i + 1];
|
||||
setCurrentPlaying(&mp3Files[i + 1]);
|
||||
return this;
|
||||
}
|
||||
useFirst = true;
|
||||
|
|
@ -190,10 +251,9 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
|
|||
// Therefore, we need to recursively look in our subdirectories.
|
||||
for (auto subdir : subdirectories)
|
||||
{
|
||||
Serial.println("searching next node");
|
||||
|
||||
if (useFirst && subdir->mp3Files.size()>0) {
|
||||
subdir->currentPlaying = &subdir->mp3Files[0];
|
||||
subdir->setCurrentPlaying(&subdir->mp3Files[0]);
|
||||
return subdir;
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +266,7 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
|
|||
if (i < subdir->mp3Files.size() - 1)
|
||||
{
|
||||
// Advance to the next MP3 file in the same directory
|
||||
subdir->currentPlaying = &subdir->mp3Files[i + 1];
|
||||
subdir->setCurrentPlaying(&subdir->mp3Files[i + 1]);
|
||||
return subdir;
|
||||
} else {
|
||||
useFirst = true;
|
||||
|
|
@ -232,12 +292,12 @@ String DirectoryNode::getDirectoryStructureHTML() const
|
|||
}
|
||||
|
||||
if (name!="/") {
|
||||
html += "<li><b>" + name + "</b></li>\n";
|
||||
html += "<li data-id=\""+String(id)+"\"><b>" + name + "</b></li>\n";
|
||||
}
|
||||
|
||||
for (const String &mp3File : mp3Files)
|
||||
for (int i=0;i<mp3Files.size();i++)
|
||||
{
|
||||
html += "<li>" + mp3File + "</li>\n";
|
||||
html += "<li data-id=\""+String(ids[i])+"\">" + mp3Files[i] + "</li>\n";
|
||||
}
|
||||
|
||||
for (DirectoryNode *childNode : subdirectories)
|
||||
|
|
|
|||
|
|
@ -4,36 +4,52 @@
|
|||
#include <SD.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
const String sys_dir = "system";
|
||||
|
||||
|
||||
|
||||
class DirectoryNode {
|
||||
private:
|
||||
uint16_t id;
|
||||
String name;
|
||||
std::vector<DirectoryNode*> subdirectories;
|
||||
std::vector<String> mp3Files;
|
||||
std::vector<uint16_t> ids;
|
||||
const String* currentPlaying;
|
||||
uint16_t currentPlayingId = 0;
|
||||
uint16_t secondsPlayed = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
DirectoryNode(const String& nodeName);
|
||||
~DirectoryNode();
|
||||
static uint16_t idCounter;
|
||||
|
||||
|
||||
const String& getName() const;
|
||||
const uint16_t getId() const;
|
||||
const std::vector<DirectoryNode*>& getSubdirectories() const;
|
||||
const std::vector<String>& getMP3Files() const;
|
||||
|
||||
void setCurrentPlaying(const String* mp3File);
|
||||
const String* getCurrentPlaying() const;
|
||||
const uint16_t getCurrentPlayingId() const;
|
||||
|
||||
void setSecondsPlayed(const uint32_t seconds);
|
||||
uint32_t getSecondsPlayed();
|
||||
|
||||
uint16_t getNextId();
|
||||
|
||||
void addSubdirectory(DirectoryNode* subdirectory);
|
||||
void addMP3File(const String& mp3File);
|
||||
void buildDirectoryTree(const char* currentPath);
|
||||
void printDirectoryTree(int level = 0) const;
|
||||
DirectoryNode* advanceToMP3(const String* currentGlobal);
|
||||
DirectoryNode* advanceToNextMP3(const String* currentGlobal);
|
||||
DirectoryNode* advanceToMP3(const uint16_t id);
|
||||
void advanceToFirstMP3InThisNode();
|
||||
String getDirectoryStructureHTML() const;
|
||||
void appendIndentation(String& html, int level) const;
|
||||
|
|
@ -41,4 +57,7 @@ public:
|
|||
String getCurrentPlayingFilePath() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* DIRECTORYNODE_H_ */
|
||||
|
|
|
|||
|
|
@ -50,8 +50,9 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
// Add click event listener to each <li> element
|
||||
liElements.forEach(function(li) {
|
||||
li.addEventListener('click', function() {
|
||||
var liText = this.innerText;
|
||||
playNamedSong(liText);
|
||||
//var liText = this.innerText;
|
||||
var id = this.dataset.id;
|
||||
playSongById(id);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -109,6 +110,22 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
|
||||
}
|
||||
|
||||
function playSongById(id) {
|
||||
var url = "/playbyid";
|
||||
var params = "id="+id;
|
||||
var http = new XMLHttpRequest();
|
||||
|
||||
http.open("GET", url+"?"+params, true);
|
||||
http.onreadystatechange = function()
|
||||
{
|
||||
if(http.readyState == 4 && http.status == 200) {
|
||||
|
||||
}
|
||||
}
|
||||
http.send(null);
|
||||
|
||||
}
|
||||
|
||||
function playNamedSong(song) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/playnamed");
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ bool playFile(const char* filename, uint32_t resumeFilePos = 0);
|
|||
|
||||
void loop2(void* parameter);
|
||||
|
||||
void named_song_action(AsyncWebServerRequest *request);
|
||||
void id_song_action(AsyncWebServerRequest *request);
|
||||
|
||||
void progress_action(AsyncWebServerRequest *request);
|
||||
|
||||
|
|
@ -71,12 +71,22 @@ const int startDelay = 250;
|
|||
|
||||
String lastUid = "";
|
||||
|
||||
uint16_t currentSongId = 0;
|
||||
|
||||
uint32_t currentSongSeconds = 0;
|
||||
|
||||
boolean continuePlaying = false;
|
||||
|
||||
boolean prepareSleepMode = false;
|
||||
|
||||
const String sleep_sound = "sleep.mp3";
|
||||
|
||||
const String startup_sound = "start.mp3";
|
||||
|
||||
const String mapping_file = "/mapping.txt";
|
||||
|
||||
const String progress_file = "/progress.txt";
|
||||
|
||||
std::map<String, String> rfid_map;
|
||||
|
||||
/*
|
||||
|
|
@ -86,9 +96,10 @@ const long sleepMessageDelay = 28000;
|
|||
const long sleepDelay = 30000;
|
||||
*/
|
||||
|
||||
const long sleepMessageDelay = 1798000;
|
||||
//const long sleepMessageDelay = 1798000;
|
||||
const long sleepMessageDelay = 22000;
|
||||
|
||||
// wait until deep sleep:
|
||||
const long sleepDelay = 1800000;
|
||||
// wait until deep sleep:1800000
|
||||
const long sleepDelay = 25000;
|
||||
|
||||
#endif
|
||||
101
src/main.cpp
101
src/main.cpp
|
|
@ -58,9 +58,14 @@ uint rfid_loop = RFID_LOOP_INTERVAL;
|
|||
AsyncWebServer server(80);
|
||||
DNSServer dns;
|
||||
|
||||
//static variable has to be instantiated outside of class definition:
|
||||
uint16_t DirectoryNode::idCounter = 0;
|
||||
|
||||
DirectoryNode rootNode("/");
|
||||
DirectoryNode *currentNode = NULL;
|
||||
|
||||
|
||||
|
||||
volatile bool newRfidInt = false;
|
||||
|
||||
MFRC522 rfid(CS_RFID, RST_RFID); // instatiate a MFRC522 reader object.
|
||||
|
|
@ -109,6 +114,24 @@ uint32_t getBatteryVoltageMv() {
|
|||
}
|
||||
|
||||
|
||||
void playSongById(uint16_t id, uint32_t continueSeconds = 0)
|
||||
{
|
||||
currentNode = rootNode.advanceToMP3(id);
|
||||
String mp3File = currentNode->getCurrentPlayingFilePath();
|
||||
Serial.print("playing by id: ");
|
||||
Serial.print(id);Serial.print(" ");Serial.println(continueSeconds);
|
||||
|
||||
Serial.println(mp3File.c_str());
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
playFile(mp3File.c_str());
|
||||
if (continueSeconds!=0) {
|
||||
audio.setAudioPlayPosition(continueSeconds);
|
||||
}
|
||||
activateRFID();
|
||||
deactivateSD();
|
||||
}
|
||||
|
||||
void playSongByName(String song)
|
||||
{
|
||||
currentNode = rootNode.advanceToMP3(&song);
|
||||
|
|
@ -203,6 +226,39 @@ void unmute()
|
|||
audio.setVolume(volume);
|
||||
}
|
||||
|
||||
void writeSongProgress(const char *filename, uint16_t id, uint32_t seconds) {
|
||||
File file = SD.open(filename, FILE_WRITE);
|
||||
if (file) {
|
||||
file.print(id);
|
||||
file.print(" ");
|
||||
file.println(seconds);
|
||||
file.close();
|
||||
Serial.println("Data written to file: ID-" + String(id) + ", Number-" + String(seconds));
|
||||
} else {
|
||||
Serial.println("Error opening file for writing.");
|
||||
}
|
||||
}
|
||||
|
||||
boolean readSongProgress(const char *filename) {
|
||||
String data = "";
|
||||
File file = SD.open(filename);
|
||||
|
||||
if (file) {
|
||||
while (file.available()) {
|
||||
char character = file.read();
|
||||
data += character;
|
||||
}
|
||||
file.close();
|
||||
// Parse the string into ID and number
|
||||
sscanf(data.c_str(), "%d %d", ¤tSongId, ¤tSongSeconds);
|
||||
Serial.println("Data read from file: " + data);
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("Error opening file for reading.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String getState()
|
||||
{
|
||||
DynamicJsonDocument jsonState(1024);
|
||||
|
|
@ -305,7 +361,7 @@ void next()
|
|||
void audio_eof_mp3(const char *info)
|
||||
{
|
||||
Serial.println("audio file ended.");
|
||||
if (continuousMode)
|
||||
if (continuousMode && !prepareSleepMode)
|
||||
playNextMp3();
|
||||
}
|
||||
|
||||
|
|
@ -364,6 +420,16 @@ void setup()
|
|||
rootNode.printDirectoryTree();
|
||||
|
||||
readDataFromFile(mapping_file.c_str());
|
||||
String progressPath = "/"+sys_dir+"/"+progress_file;
|
||||
|
||||
continuePlaying = readSongProgress(progressPath.c_str());
|
||||
|
||||
if (continuePlaying) {
|
||||
Serial.print("deleting ");
|
||||
Serial.println(progressPath.c_str());
|
||||
SD.remove(progressPath.c_str());
|
||||
}
|
||||
|
||||
|
||||
deactivateSD();
|
||||
activateRFID();
|
||||
|
|
@ -438,7 +504,7 @@ void setup()
|
|||
request->send(200, "text/plain", "next");
|
||||
next(); });
|
||||
|
||||
server.on("/playnamed", HTTP_POST, named_song_action);
|
||||
server.on("/playbyid", HTTP_GET, id_song_action);
|
||||
|
||||
server.on("/progress", HTTP_POST, progress_action);
|
||||
|
||||
|
|
@ -466,23 +532,24 @@ void setup()
|
|||
Serial.println("initialization done.");
|
||||
}
|
||||
|
||||
void named_song_action(AsyncWebServerRequest *request)
|
||||
void id_song_action(AsyncWebServerRequest *request)
|
||||
{
|
||||
Serial.println("named song!");
|
||||
Serial.println("song by id!");
|
||||
|
||||
int params = request->params();
|
||||
for (int i = 0; i < params; i++)
|
||||
{
|
||||
AsyncWebParameter *p = request->getParam(i);
|
||||
if (p->name() == "title")
|
||||
if (p->name() == "id")
|
||||
{
|
||||
playSongByName(p->value());
|
||||
playSongById(atoi(p->value().c_str()));
|
||||
}
|
||||
}
|
||||
lastInteraction = millis();
|
||||
request->send_P(200, "text/plain", "ok");
|
||||
}
|
||||
|
||||
|
||||
void progress_action(AsyncWebServerRequest *request)
|
||||
{
|
||||
Serial.println("progress!");
|
||||
|
|
@ -529,13 +596,10 @@ void loop()
|
|||
deactivateRFID();
|
||||
activateSD();
|
||||
audio.loop();
|
||||
if (currentNode != NULL)
|
||||
if (currentNode != NULL && !prepareSleepMode)
|
||||
{
|
||||
currentNode->setSecondsPlayed(audio.getAudioCurrentTime());
|
||||
}
|
||||
|
||||
deactivateSD();
|
||||
activateRFID();
|
||||
}
|
||||
else if (asyncStart)
|
||||
{
|
||||
|
|
@ -543,7 +607,11 @@ void loop()
|
|||
start();
|
||||
}
|
||||
|
||||
if (!startupSoundPlayed) {
|
||||
if (continuePlaying) {
|
||||
continuePlaying = false;
|
||||
startupSoundPlayed = true;
|
||||
playSongById(currentSongId,currentSongSeconds);
|
||||
} else if (!startupSoundPlayed) {
|
||||
startupSoundPlayed = true;
|
||||
String tempPath = "/"+sys_dir+"/"+startup_sound;
|
||||
playSongByPath(tempPath.c_str());
|
||||
|
|
@ -554,8 +622,15 @@ void loop()
|
|||
// send device to sleep:
|
||||
long now = millis();
|
||||
|
||||
if (!sleepSoundPlayed && now - lastInteraction > sleepMessageDelay) {
|
||||
if (!sleepSoundPlayed && now - lastInteraction > sleepMessageDelay) {
|
||||
sleepSoundPlayed = true;
|
||||
prepareSleepMode = true;
|
||||
if (currentNode != NULL) {
|
||||
String progressPath = "/"+sys_dir+"/"+progress_file;
|
||||
|
||||
writeSongProgress(progressPath.c_str(),currentNode->getCurrentPlayingId(),currentNode->getSecondsPlayed());
|
||||
}
|
||||
|
||||
String tempPath = "/"+sys_dir+"/"+sleep_sound;
|
||||
playSongByPath(tempPath.c_str());
|
||||
}
|
||||
|
|
@ -563,7 +638,7 @@ void loop()
|
|||
|
||||
if (now - lastInteraction > sleepDelay) {
|
||||
Serial.println("entering deep sleep...");
|
||||
deactivateRFID();
|
||||
deactivateRFID();
|
||||
deactivateSD();
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue