ids, resume function

This commit is contained in:
Stefan Ostermann 2023-10-21 21:54:56 +02:00
parent 578281d9d1
commit 9c4b1d4913
5 changed files with 213 additions and 31 deletions

View File

@ -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)

View File

@ -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_ */

View File

@ -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");

View File

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

View File

@ -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", &currentSongId, &currentSongSeconds);
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();
}