Previous, low voltage sleep

This commit is contained in:
Stefan Ostermann 2023-12-03 20:03:18 +01:00
parent 5814a73f50
commit 83b5e1c5e9
4 changed files with 151 additions and 42 deletions

View File

@ -1,11 +1,11 @@
#include "DirectoryNode.h" #include "DirectoryNode.h"
DirectoryNode::DirectoryNode(const String &nodeName) DirectoryNode::DirectoryNode(const String &nodeName)
: name(nodeName), currentPlaying(nullptr) { : name(nodeName), currentPlaying(nullptr)
id = DirectoryNode::idCounter; {
DirectoryNode::idCounter++; id = DirectoryNode::idCounter;
} DirectoryNode::idCounter++;
}
DirectoryNode::~DirectoryNode() DirectoryNode::~DirectoryNode()
{ {
@ -15,7 +15,6 @@ DirectoryNode::~DirectoryNode()
} }
} }
const uint16_t DirectoryNode::getId() const const uint16_t DirectoryNode::getId() const
{ {
return id; return id;
@ -39,8 +38,10 @@ const std::vector<String> &DirectoryNode::getMP3Files() const
void DirectoryNode::setCurrentPlaying(const String *mp3File) void DirectoryNode::setCurrentPlaying(const String *mp3File)
{ {
currentPlaying = mp3File; currentPlaying = mp3File;
for (int i=0;i<mp3Files.size();i++) { for (int i = 0; i < mp3Files.size(); i++)
if (mp3Files[i] == *mp3File && ids.size()>i) { {
if (mp3Files[i] == *mp3File && ids.size() > i)
{
currentPlayingId = ids[i]; currentPlayingId = ids[i];
} }
} }
@ -56,7 +57,8 @@ const uint16_t DirectoryNode::getCurrentPlayingId() const
return currentPlayingId; return currentPlayingId;
} }
uint16_t DirectoryNode::getNextId() { uint16_t DirectoryNode::getNextId()
{
uint16_t next = DirectoryNode::idCounter; uint16_t next = DirectoryNode::idCounter;
DirectoryNode::idCounter++; DirectoryNode::idCounter++;
return next; return next;
@ -70,14 +72,16 @@ void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory)
void DirectoryNode::addMP3File(const String &mp3File) void DirectoryNode::addMP3File(const String &mp3File)
{ {
mp3Files.push_back(mp3File); mp3Files.push_back(mp3File);
ids.push_back(getNextId()); ids.push_back(getNextId());
} }
void DirectoryNode::setSecondsPlayed(const uint32_t seconds) { void DirectoryNode::setSecondsPlayed(const uint32_t seconds)
{
secondsPlayed = seconds; secondsPlayed = seconds;
} }
uint32_t DirectoryNode::getSecondsPlayed() { uint32_t DirectoryNode::getSecondsPlayed()
{
return secondsPlayed; return secondsPlayed;
} }
@ -92,7 +96,7 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
break; break;
} }
if (entry.isDirectory() && entry.name()[0] != '.' && 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()); DirectoryNode *newNode = new DirectoryNode(entry.name());
subdirectories.push_back(newNode); subdirectories.push_back(newNode);
@ -153,20 +157,23 @@ DirectoryNode *DirectoryNode::findFirstDirectoryWithMP3s()
return nullptr; return nullptr;
} }
void DirectoryNode::advanceToFirstMP3InThisNode() { void DirectoryNode::advanceToFirstMP3InThisNode()
if (mp3Files.size()>0) { {
if (mp3Files.size() > 0)
{
setCurrentPlaying(&mp3Files[0]); setCurrentPlaying(&mp3Files[0]);
} }
} }
DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
DirectoryNode* DirectoryNode::advanceToMP3(const uint16_t id) { {
for (auto subdir : subdirectories) for (auto subdir : subdirectories)
{ {
if (subdir->getId()==id) { if (subdir->getId() == id)
{
subdir->advanceToFirstMP3InThisNode(); subdir->advanceToFirstMP3InThisNode();
return subdir; return subdir;
} }
// Have each subdirectory advance its song // Have each subdirectory advance its song
for (size_t i = 0; i < subdir->ids.size(); i++) for (size_t i = 0; i < subdir->ids.size(); i++)
@ -179,8 +186,7 @@ for (auto subdir : subdirectories)
subdir->currentPlaying = &subdir->mp3Files[i]; subdir->currentPlaying = &subdir->mp3Files[i];
subdir->currentPlayingId = id; subdir->currentPlayingId = id;
return subdir; return subdir;
} }
} }
} }
} }
@ -191,14 +197,15 @@ for (auto subdir : subdirectories)
return this; return this;
} }
DirectoryNode *DirectoryNode::advanceToMP3(const String *currentGlobal)
DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) { {
for (auto subdir : subdirectories) for (auto subdir : subdirectories)
{ {
if (subdir->getName()==*currentGlobal) { if (subdir->getName() == *currentGlobal)
{
subdir->advanceToFirstMP3InThisNode(); subdir->advanceToFirstMP3InThisNode();
return subdir; return subdir;
} }
// Have each subdirectory advance its song // Have each subdirectory advance its song
for (size_t i = 0; i < subdir->mp3Files.size(); i++) for (size_t i = 0; i < subdir->mp3Files.size(); i++)
@ -210,8 +217,7 @@ DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) {
{ {
subdir->setCurrentPlaying(&subdir->mp3Files[i]); subdir->setCurrentPlaying(&subdir->mp3Files[i]);
return subdir; return subdir;
} }
} }
} }
} }
@ -222,7 +228,50 @@ DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) {
return this; return this;
} }
DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) /**
* Moves to the previous MP3 file in the directory.
* If the current song has been playing for more than a specific threshold, restarts the current song.
* If the current song has just started, or it's the first song, moves to the previous song in the directory.
*
* @param thresholdSeconds The number of seconds to decide whether to restart the current song or go to the previous song.
* @return A pointer to the DirectoryNode where the new current song is located, or nullptr if there's no previous song.
*/
DirectoryNode *DirectoryNode::goToPreviousMP3(uint32_t thresholdSeconds)
{
if (secondsPlayed > thresholdSeconds || currentPlaying == nullptr)
{
// Restart the current song if it's been playing for more than thresholdSeconds
// Or if there is no current song (at the start of the list)
return this;
}
else
{
// Find the previous song
for (size_t i = 0; i < mp3Files.size(); i++)
{
if (currentPlaying != nullptr && *currentPlaying == mp3Files[i] && i > 0)
{
// Move to the previous song
setCurrentPlaying(&mp3Files[i - 1]);
return this;
}
}
// If the first song in the directory or no song was playing, move to the previous directory, if any
for (auto subdir : subdirectories)
{
DirectoryNode *previousNode = subdir->goToPreviousMP3(thresholdSeconds);
if (previousNode != nullptr)
{
return previousNode;
}
}
}
// No previous song available
return nullptr;
}
DirectoryNode *DirectoryNode::advanceToNextMP3(const String *currentGlobal)
{ {
bool useFirst = false; bool useFirst = false;
Serial.println(currentGlobal->c_str()); Serial.println(currentGlobal->c_str());
@ -230,7 +279,7 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
{ {
for (size_t i = 0; i < mp3Files.size(); i++) for (size_t i = 0; i < mp3Files.size(); i++)
{ {
if (*currentGlobal==mp3Files[i]) if (*currentGlobal == mp3Files[i])
{ {
// Found the current playing MP3 file // Found the current playing MP3 file
if (i < mp3Files.size() - 1) if (i < mp3Files.size() - 1)
@ -245,14 +294,14 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
} }
} }
} }
// We are either not playing, or we've exhausted all the MP3 files in this directory. // We are either not playing, or we've exhausted all the MP3 files in this directory.
// Therefore, we need to recursively look in our subdirectories. // Therefore, we need to recursively look in our subdirectories.
for (auto subdir : subdirectories) for (auto subdir : subdirectories)
{ {
if (useFirst && subdir->mp3Files.size()>0) { if (useFirst && subdir->mp3Files.size() > 0)
{
subdir->setCurrentPlaying(&subdir->mp3Files[0]); subdir->setCurrentPlaying(&subdir->mp3Files[0]);
return subdir; return subdir;
} }
@ -268,7 +317,9 @@ DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal)
// Advance to the next MP3 file in the same directory // Advance to the next MP3 file in the same directory
subdir->setCurrentPlaying(&subdir->mp3Files[i + 1]); subdir->setCurrentPlaying(&subdir->mp3Files[i + 1]);
return subdir; return subdir;
} else { }
else
{
useFirst = true; useFirst = true;
} }
// Reached the end of the MP3 files in the directory // Reached the end of the MP3 files in the directory
@ -287,24 +338,27 @@ String DirectoryNode::getDirectoryStructureHTML() const
{ {
String html; String html;
html.reserve(1024); // Reserve memory for better performance html.reserve(1024); // Reserve memory for better performance
if (name=="/") { if (name == "/")
{
html += "<ul>\n"; html += "<ul>\n";
} }
if (name!="/") { if (name != "/")
html += "<li data-id=\""+String(id)+"\"><b>" + name + "</b></li>\n"; {
html += "<li data-id=\"" + String(id) + "\"><b>" + name + "</b></li>\n";
} }
for (int i=0;i<mp3Files.size();i++) for (int i = 0; i < mp3Files.size(); i++)
{ {
html += "<li data-id=\""+String(ids[i])+"\">" + mp3Files[i] + "</li>\n"; html += "<li data-id=\"" + String(ids[i]) + "\">" + mp3Files[i] + "</li>\n";
} }
for (DirectoryNode *childNode : subdirectories) for (DirectoryNode *childNode : subdirectories)
{ {
html += childNode->getDirectoryStructureHTML(); html += childNode->getDirectoryStructureHTML();
} }
if (name=="/") { if (name == "/")
{
html += "</ul>\n"; html += "</ul>\n";
} }

View File

@ -49,6 +49,7 @@ public:
void printDirectoryTree(int level = 0) const; void printDirectoryTree(int level = 0) const;
DirectoryNode* advanceToMP3(const String* currentGlobal); DirectoryNode* advanceToMP3(const String* currentGlobal);
DirectoryNode* advanceToNextMP3(const String* currentGlobal); DirectoryNode* advanceToNextMP3(const String* currentGlobal);
DirectoryNode* goToPreviousMP3(uint32_t thresholdSeconds = 3);
DirectoryNode* advanceToMP3(const uint16_t id); DirectoryNode* advanceToMP3(const uint16_t id);
void advanceToFirstMP3InThisNode(); void advanceToFirstMP3InThisNode();
String getDirectoryStructureHTML() const; String getDirectoryStructureHTML() const;

View File

@ -14,7 +14,7 @@ const char index_html[] PROGMEM = R"rawliteral(
<span id="uid"></span><br/> <span id="uid"></span><br/>
<div> <div>
<button class="prev-button" onclick="simpleGetCall('prev');""></button> <button class="prev-button" onclick="simpleGetCall('previous');""></button>
<button class="play-button" onclick="simpleGetCall('toggleplaypause');"></button> <button class="play-button" onclick="simpleGetCall('toggleplaypause');"></button>
<button class="next-button" onclick="simpleGetCall('next');"></button><br/><br/> <button class="next-button" onclick="simpleGetCall('next');"></button><br/><br/>
</div> </div>

View File

@ -37,6 +37,8 @@
#define VOLTAGE_LOOP_INTERVAL 5000 #define VOLTAGE_LOOP_INTERVAL 5000
#define VOLTAGE_THRESHOLD 3800
#include "globals.h" #include "globals.h"
#include "WebContent.h" #include "WebContent.h"
#include "css.h" #include "css.h"
@ -82,6 +84,8 @@ bool asyncNext = false;
bool asyncPrev = false; bool asyncPrev = false;
uint16_t voltage_threshold_counter = 0;
/* /*
std::map<String, String> rfid_map{{"67 152 204 14", "01-The_Box_Tops-The_Letter.mp3"}, std::map<String, String> rfid_map{{"67 152 204 14", "01-The_Box_Tops-The_Letter.mp3"},
{"67 175 148 160", "068-Der_Schatz_im_Bergsee"}}; {"67 175 148 160", "068-Der_Schatz_im_Bergsee"}};
@ -360,6 +364,37 @@ void next()
lastInteraction = millis(); lastInteraction = millis();
} }
void previous()
{
if (currentNode != nullptr) {
const String* curr = currentNode->getCurrentPlaying();
DirectoryNode* newNode = currentNode->goToPreviousMP3();
if (newNode != nullptr) {
if (curr == newNode->getCurrentPlaying()) {
// reset to 0 seconds playtime:
audio.setAudioPlayPosition(0);
} else {
// Update the current node and start playing the previous song
Serial.println("");
Serial.print("Playing previous song: ");
Serial.println(currentNode->getCurrentPlayingFilePath());
currentNode = newNode;
stop();
deactivateRFID();
activateSD();
playSongByPath(currentNode->getCurrentPlayingFilePath());
deactivateSD();
activateRFID();
}
}
}
lastInteraction = millis();
}
void audio_eof_mp3(const char *info) void audio_eof_mp3(const char *info)
{ {
Serial.println("audio file ended."); Serial.println("audio file ended.");
@ -511,6 +546,12 @@ void setup()
request->send(200, "text/plain", "next"); request->send(200, "text/plain", "next");
next(); }); next(); });
server.on("/previous", HTTP_GET, [](AsyncWebServerRequest *request)
{
request->send(200, "text/plain", "previous");
previous(); });
server.on("/playbyid", HTTP_GET, id_song_action); server.on("/playbyid", HTTP_GET, id_song_action);
server.on("/progress", HTTP_POST, progress_action); server.on("/progress", HTTP_POST, progress_action);
@ -663,7 +704,8 @@ void loop()
else if (asyncPrev) else if (asyncPrev)
{ {
asyncPrev = false; asyncPrev = false;
Serial.println("Previous not yet implemented!"); Serial.println("Previous");
previous();
} }
@ -682,6 +724,18 @@ void loop()
if (loopCounter % VOLTAGE_LOOP_INTERVAL == 0) if (loopCounter % VOLTAGE_LOOP_INTERVAL == 0)
{ {
lastVoltage = getBatteryVoltageMv(); lastVoltage = getBatteryVoltageMv();
if (lastVoltage<VOLTAGE_THRESHOLD) {
if (voltage_threshold_counter>3) {
Serial.println("entering deep sleep due to low voltage...");
lastInteraction = millis() - sleepMessageDelay;
voltage_threshold_counter = 0;
} else {
voltage_threshold_counter++;
}
} else {
voltage_threshold_counter = 0;
}
} }
loopCounter++; loopCounter++;