DirectoryNode structure
This commit is contained in:
parent
2b97967326
commit
2dd95a35eb
13
README.md
13
README.md
|
|
@ -1,12 +1,17 @@
|
|||
# HannaBox
|
||||
Manual install of wifi manager download zip in project dir using vs console:
|
||||
|
||||
pio lib install ~/Downloads/WiFiManager-2.0.16-rc.2.zip
|
||||
## Microcontroller
|
||||
|
||||
D1 Mini ESP32
|
||||
Due to mp3 playback it needs a multicore esp 32:
|
||||
|
||||
This library only works on multi-core ESP32 chips like the ESP32-S3. It does not work on the ESP32-S2 or the ESP32-C3 warning
|
||||
|
||||
## Pins
|
||||
|
||||
```
|
||||
Amplifier:
|
||||
RX -> DIN
|
||||
25 -> DIN
|
||||
D8 -> BCLK
|
||||
D4 -> LRC
|
||||
5V -> Vin
|
||||
|
|
@ -19,6 +24,8 @@ CS -> D1
|
|||
MOSI -> D7
|
||||
CLK -> D5
|
||||
MISO -> D6
|
||||
```
|
||||
|
||||
|
||||
## Links
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
#include "DirectoryNode.h"
|
||||
|
||||
DirectoryNode::DirectoryNode(const String &nodeName)
|
||||
: name(nodeName), currentPlaying(nullptr) {}
|
||||
|
||||
DirectoryNode::~DirectoryNode()
|
||||
{
|
||||
for (DirectoryNode *childNode : subdirectories)
|
||||
{
|
||||
delete childNode;
|
||||
}
|
||||
}
|
||||
|
||||
const String &DirectoryNode::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::vector<DirectoryNode *> &DirectoryNode::getSubdirectories() const
|
||||
{
|
||||
return subdirectories;
|
||||
}
|
||||
|
||||
const std::vector<String> &DirectoryNode::getMP3Files() const
|
||||
{
|
||||
return mp3Files;
|
||||
}
|
||||
|
||||
void DirectoryNode::setCurrentPlaying(const String *mp3File)
|
||||
{
|
||||
currentPlaying = mp3File;
|
||||
}
|
||||
|
||||
const String *DirectoryNode::getCurrentPlaying() const
|
||||
{
|
||||
return currentPlaying;
|
||||
}
|
||||
|
||||
void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory)
|
||||
{
|
||||
subdirectories.push_back(subdirectory);
|
||||
}
|
||||
|
||||
void DirectoryNode::addMP3File(const String &mp3File)
|
||||
{
|
||||
mp3Files.push_back(mp3File);
|
||||
}
|
||||
|
||||
void DirectoryNode::buildDirectoryTree(const char *currentPath)
|
||||
{
|
||||
File rootDir = SD.open(currentPath);
|
||||
while (true)
|
||||
{
|
||||
File entry = rootDir.openNextFile();
|
||||
if (!entry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
DirectoryNode *newNode = new DirectoryNode(entry.name());
|
||||
subdirectories.push_back(newNode);
|
||||
newNode->buildDirectoryTree((String(currentPath) + entry.name()).c_str());
|
||||
}
|
||||
else if (String(entry.name()).endsWith(".mp3"))
|
||||
{
|
||||
mp3Files.push_back(entry.name());
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
rootDir.close();
|
||||
}
|
||||
|
||||
void DirectoryNode::printDirectoryTree(int level) const
|
||||
{
|
||||
for (int i = 0; i < level; i++)
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println(name);
|
||||
|
||||
for (const String &mp3File : mp3Files)
|
||||
{
|
||||
for (int i = 0; i <= level; i++)
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println(mp3File);
|
||||
}
|
||||
|
||||
for (DirectoryNode *childNode : subdirectories)
|
||||
{
|
||||
childNode->printDirectoryTree(level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryNode *DirectoryNode::findFirstDirectoryWithMP3s()
|
||||
{
|
||||
if (!mp3Files.empty())
|
||||
{
|
||||
// Found a directory with MP3 files
|
||||
return this;
|
||||
}
|
||||
|
||||
for (DirectoryNode *subdirectory : subdirectories)
|
||||
{
|
||||
DirectoryNode *result = subdirectory->findFirstDirectoryWithMP3s();
|
||||
if (result != nullptr)
|
||||
{
|
||||
// Found a directory with MP3 files in the subdirectories
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// No directory with MP3 files found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DirectoryNode::advanceToNextMP3()
|
||||
{
|
||||
if (currentPlaying != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < mp3Files.size(); i++)
|
||||
{
|
||||
if (*currentPlaying == 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];
|
||||
return;
|
||||
}
|
||||
// Reached the end of the MP3 files in the directory
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If not playing or reached the end, set the first MP3 file as the current playing
|
||||
if (!mp3Files.empty())
|
||||
{
|
||||
currentPlaying = &mp3Files[0];
|
||||
}
|
||||
}
|
||||
|
||||
String DirectoryNode::getDirectoryStructureHTML() const
|
||||
{
|
||||
String html;
|
||||
html.reserve(1024); // Reserve memory for better performance
|
||||
|
||||
appendIndentation(html, 0);
|
||||
html += "<ul>\n";
|
||||
appendIndentation(html, 1);
|
||||
html += "<li>" + name + "</li>\n";
|
||||
|
||||
for (const String &mp3File : mp3Files)
|
||||
{
|
||||
appendIndentation(html, 2);
|
||||
html += "<li>" + mp3File + "</li>\n";
|
||||
}
|
||||
|
||||
for (DirectoryNode *childNode : subdirectories)
|
||||
{
|
||||
html += childNode->getDirectoryStructureHTML();
|
||||
}
|
||||
|
||||
appendIndentation(html, 0);
|
||||
html += "</ul>\n";
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
void DirectoryNode::appendIndentation(String &html, int level) const
|
||||
{
|
||||
for (int i = 0; i < level; i++)
|
||||
{
|
||||
html += " ";
|
||||
}
|
||||
}
|
||||
|
||||
String DirectoryNode::getCurrentPlayingFilePath() const
|
||||
{
|
||||
if (currentPlaying != nullptr)
|
||||
{
|
||||
String filePath = "/" + name;
|
||||
if (!filePath.endsWith("/"))
|
||||
{
|
||||
filePath += "/";
|
||||
}
|
||||
filePath += *currentPlaying;
|
||||
return filePath;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef DIRECTORYNODE_H_
|
||||
#define DIRECTORYNODE_H_
|
||||
|
||||
#include <SD.h>
|
||||
#include <vector>
|
||||
|
||||
class DirectoryNode {
|
||||
private:
|
||||
String name;
|
||||
std::vector<DirectoryNode*> subdirectories;
|
||||
std::vector<String> mp3Files;
|
||||
const String* currentPlaying;
|
||||
|
||||
public:
|
||||
DirectoryNode(const String& nodeName);
|
||||
~DirectoryNode();
|
||||
|
||||
const String& getName() const;
|
||||
const std::vector<DirectoryNode*>& getSubdirectories() const;
|
||||
const std::vector<String>& getMP3Files() const;
|
||||
|
||||
void setCurrentPlaying(const String* mp3File);
|
||||
const String* getCurrentPlaying() const;
|
||||
|
||||
void addSubdirectory(DirectoryNode* subdirectory);
|
||||
void addMP3File(const String& mp3File);
|
||||
void buildDirectoryTree(const char* currentPath);
|
||||
void printDirectoryTree(int level = 0) const;
|
||||
void advanceToNextMP3();
|
||||
String getDirectoryStructureHTML() const;
|
||||
void appendIndentation(String& html, int level) const;
|
||||
DirectoryNode* findFirstDirectoryWithMP3s();
|
||||
String getCurrentPlayingFilePath() const;
|
||||
};
|
||||
|
||||
#endif /* DIRECTORYNODE_H_ */
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
#ifndef HELPER_H_
|
||||
#define HELPER_H_
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
|
||||
struct DirectoryNode {
|
||||
String name;
|
||||
std::vector<DirectoryNode*> subdirectories;
|
||||
std::vector<String> mp3Files;
|
||||
String* currentPlaying;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void buildDirectoryTree(DirectoryNode* currentNode, const char* currentPath) {
|
||||
File root = SD.open(currentPath);
|
||||
while (true) {
|
||||
File entry = root.openNextFile();
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
DirectoryNode* newNode = new DirectoryNode;
|
||||
newNode->name = String(currentPath) + entry.name();
|
||||
currentNode->subdirectories.push_back(newNode);
|
||||
buildDirectoryTree(newNode, (String(currentPath) + entry.name()).c_str());
|
||||
} else if (String(entry.name()).endsWith(".mp3")) {
|
||||
currentNode->mp3Files.push_back(entry.name());
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
root.close();
|
||||
}
|
||||
|
||||
void printDirectoryTree(DirectoryNode* currentNode, int level = 0) {
|
||||
for (int i = 0; i < level; i++) {
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println(currentNode->name);
|
||||
|
||||
for (const String& mp3File : currentNode->mp3Files) {
|
||||
for (int i = 0; i <= level; i++) {
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println(mp3File);
|
||||
}
|
||||
|
||||
for (DirectoryNode* childNode : currentNode->subdirectories) {
|
||||
printDirectoryTree(childNode, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void advanceToNextMP3(DirectoryNode* currentNode) {
|
||||
if (currentNode->currentPlaying != nullptr) {
|
||||
for (size_t i = 0; i < currentNode->mp3Files.size(); i++) {
|
||||
if (*currentNode->currentPlaying == currentNode->mp3Files[i]) {
|
||||
// Found the current playing MP3 file
|
||||
if (i < currentNode->mp3Files.size() - 1) {
|
||||
// Advance to the next MP3 file in the same directory
|
||||
currentNode->currentPlaying = ¤tNode->mp3Files[i + 1];
|
||||
return;
|
||||
}
|
||||
// Reached the end of the MP3 files in the directory
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If not playing or reached the end, set the first MP3 file as the current playing
|
||||
if (!currentNode->mp3Files.empty()) {
|
||||
currentNode->currentPlaying = ¤tNode->mp3Files[0];
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryNode* findFirstMP3Node(DirectoryNode* currentNode) {
|
||||
if (!currentNode->mp3Files.empty()) {
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
for (DirectoryNode* subdirectory : currentNode->subdirectories) {
|
||||
DirectoryNode* tempNode = findFirstMP3Node(subdirectory);
|
||||
if (!tempNode->mp3Files.empty()) {
|
||||
return tempNode;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* HELPER_H_ */
|
||||
67
src/main.cpp
67
src/main.cpp
|
|
@ -17,26 +17,30 @@
|
|||
#include <SD.h>
|
||||
|
||||
#include "WebContent.h"
|
||||
#include "DirectoryNode.h"
|
||||
|
||||
File root;
|
||||
File mp3File;
|
||||
|
||||
void printDirectory(File dir, int numTabs);
|
||||
|
||||
unsigned long lastStart = 0;
|
||||
|
||||
const int startDelay = 250;
|
||||
|
||||
Audio audio;
|
||||
|
||||
// Set web server port number to 80
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebServer server2(81);
|
||||
DNSServer dns;
|
||||
File next;
|
||||
|
||||
// Variable to store the HTTP request
|
||||
String header;
|
||||
|
||||
|
||||
DirectoryNode rootNode("/");
|
||||
DirectoryNode* currentNode = NULL;
|
||||
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
|
||||
|
||||
void playNextMp3()
|
||||
{
|
||||
|
|
@ -111,7 +115,11 @@ void setup()
|
|||
}
|
||||
Serial.println("SD initialization done.");
|
||||
|
||||
root = SD.open("/");
|
||||
rootNode.buildDirectoryTree("/");
|
||||
rootNode.printDirectoryTree();
|
||||
//printDirectoryTree(&rootNode, 0);
|
||||
|
||||
|
||||
// printDirectory(root, 0);
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(12); // 0...21
|
||||
|
|
@ -129,44 +137,12 @@ void setup()
|
|||
request->send(200, "text/plain", "stop");
|
||||
});
|
||||
|
||||
|
||||
server.begin();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printDirectory(File dir, int numTabs)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
|
||||
File entry = dir.openNextFile();
|
||||
if (!entry)
|
||||
{
|
||||
// no more files
|
||||
break;
|
||||
}
|
||||
for (uint8_t i = 0; i < numTabs; i++)
|
||||
{
|
||||
Serial.print('\t');
|
||||
}
|
||||
Serial.print(entry.name());
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
Serial.println("/");
|
||||
printDirectory(entry, numTabs + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// files have sizes, directories do not
|
||||
Serial.print("\t\t");
|
||||
Serial.println(entry.size(), DEC);
|
||||
}
|
||||
entry.close();
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
|
@ -178,7 +154,18 @@ void loop()
|
|||
unsigned long now = millis();
|
||||
if (now - lastStart > startDelay)
|
||||
{
|
||||
playNextMp3();
|
||||
if (currentNode==NULL) {
|
||||
currentNode = rootNode.findFirstDirectoryWithMP3s();
|
||||
if (currentNode) {
|
||||
currentNode->advanceToNextMP3();
|
||||
}
|
||||
} else {
|
||||
currentNode->advanceToNextMP3();
|
||||
}
|
||||
Serial.print("Now advancing to ");
|
||||
String mp3File = currentNode->getCurrentPlayingFilePath();
|
||||
Serial.println(mp3File.c_str());
|
||||
audio.connecttoSD(mp3File.c_str());
|
||||
Serial.println("mp3 started.");
|
||||
lastStart = now;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue