Cleanups. Delete+Move works now.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "DirectoryNode.h"
|
||||
#include "globals.h"
|
||||
|
||||
DirectoryNode::DirectoryNode(const String &nodeName)
|
||||
: name(nodeName), currentPlaying(nullptr)
|
||||
@@ -465,7 +466,7 @@ String DirectoryNode::getCurrentPlayingFilePath() const
|
||||
{
|
||||
if (currentPlaying != nullptr)
|
||||
{
|
||||
String filePath = "/" + name;
|
||||
String filePath = name;
|
||||
if (!filePath.endsWith("/"))
|
||||
{
|
||||
filePath += "/";
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
|
||||
const String sys_dir = "system";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// HTML web page
|
||||
const char index_html[] PROGMEM = R"rawliteral(
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<title>HannaBox</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel='stylesheet' href='/style.css' type='text/css' media='all' />
|
||||
</head>
|
||||
<body>
|
||||
<h1>🎵 HannaBox 🎵</h1>
|
||||
<span id="state"></span><br/><br/>
|
||||
<span id="voltage"></span><br/>
|
||||
<span id="uid"></span><br/>
|
||||
<span id="heap"></span><br/>
|
||||
|
||||
<div>
|
||||
<button class="prev-button" onclick="simpleGetCall('previous');""></button>
|
||||
<button class="play-button" onclick="simpleGetCall('toggleplaypause');"></button>
|
||||
<button class="next-button" onclick="simpleGetCall('next');"></button><br/><br/>
|
||||
</div>
|
||||
<div class="slidecontainer">
|
||||
|
||||
<input name="progress" type="range" min="0" max="100" value="0" class="slider" id="progressSlider"
|
||||
onchange="postValue('progress',document.getElementById('progressSlider').value);lastChange = Date.now();userIsInteracting = false;"
|
||||
oninput="userIsInteracting = true;"
|
||||
>
|
||||
<label for="progress" id="progressLabel"></label>
|
||||
</div>
|
||||
<div class="slidecontainer">
|
||||
<input name="volume" type="range" min="0" max="15" value="7" class="slider" id="volumeSlider"
|
||||
onchange="postValue('volume',document.getElementById('volumeSlider').value);lastChange = Date.now()"
|
||||
>
|
||||
<label for="volume">Vol</label>
|
||||
</div>
|
||||
<!--
|
||||
<button onmouseup="simpleGetCall('stop');" ontouchend="simpleGetCall('stop');">Stop</button>
|
||||
-->
|
||||
|
||||
<p class="playlist-container">
|
||||
<h2>🎶 Playlist 🎶</h2>
|
||||
%DIRECTORY%
|
||||
</p>
|
||||
|
||||
<form id="uploadForm" method="POST" action="/upload" enctype="multipart/form-data">
|
||||
<input type="file" name="data" id="uploadFile" accept=".mp3,.wav,.flac,.m4a,.ogg"/>
|
||||
<input type="submit" name="upload" value="Upload" title="Upload Audio File" id="uploadButton"/>
|
||||
<div id="uploadStatus"></div>
|
||||
<div id="uploadProgress" style="display: none;">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="progressFill"></div>
|
||||
</div>
|
||||
<span id="progressText">0%</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<h2>Edit RFID Mapping</h2>
|
||||
<form id="editMappingForm">
|
||||
<label for="rfid">RFID:</label>
|
||||
<input type="text" id="rfid" name="rfid" required><br>
|
||||
<label for="song">Song:</label>
|
||||
<input type="text" id="song" name="song" required><br>
|
||||
<button type="button" onclick="editMapping()">Update Mapping</button>
|
||||
</form>
|
||||
|
||||
<script src="/script.js"></script>
|
||||
</body>
|
||||
</html>)rawliteral";
|
||||
@@ -1,3 +0,0 @@
|
||||
// CSS content moved to SD card at /system/style.css
|
||||
// This saves approximately 4KB of flash memory
|
||||
const char css[] PROGMEM = "";
|
||||
@@ -1,93 +1,23 @@
|
||||
#ifndef GLOBALS_H_
|
||||
#define GLOBALS_H_
|
||||
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
|
||||
bool playFile(const char* filename, uint32_t resumeFilePos = 0);
|
||||
|
||||
void loop2(void* parameter);
|
||||
|
||||
void id_song_action(AsyncWebServerRequest *request);
|
||||
|
||||
void progress_action(AsyncWebServerRequest *request);
|
||||
|
||||
void volume_action(AsyncWebServerRequest *request);
|
||||
|
||||
boolean buttonPressed(const uint8_t pin);
|
||||
|
||||
/**
|
||||
* Helper routine to dump a byte array as hex values to Serial.
|
||||
*/
|
||||
void dump_byte_array(byte *buffer, byte bufferSize)
|
||||
{
|
||||
for (byte i = 0; i < bufferSize; i++)
|
||||
{
|
||||
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
|
||||
Serial.print(buffer[i], HEX);
|
||||
}
|
||||
}
|
||||
|
||||
String getRFIDString(byte uidByte[10])
|
||||
{
|
||||
String uidString = String(uidByte[0]) + " " + String(uidByte[1]) + " " +
|
||||
String(uidByte[2]) + " " + String(uidByte[3]);
|
||||
return uidString;
|
||||
}
|
||||
|
||||
void writeFile(fs::FS &fs, const char * path, const char * message){
|
||||
Serial.printf("Writing file: %s\n", path);
|
||||
|
||||
File file = fs.open(path, FILE_WRITE);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
if(file.print(message)){
|
||||
Serial.println("File written");
|
||||
} else {
|
||||
Serial.println("Write failed");
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
unsigned long lastStart = 0;
|
||||
|
||||
unsigned long lastInteraction = 0;
|
||||
|
||||
boolean sleepSoundPlayed = false;
|
||||
|
||||
boolean startupSoundPlayed = false;
|
||||
|
||||
boolean continuousMode = false;
|
||||
|
||||
uint8_t buttontoignore = 0;
|
||||
|
||||
uint32_t lastVoltage = 0;
|
||||
|
||||
uint loopCounter = 0;
|
||||
|
||||
String lastUid = "";
|
||||
|
||||
uint16_t currentSongId = 0;
|
||||
|
||||
uint32_t currentSongSeconds = 0;
|
||||
|
||||
boolean continuePlaying = false;
|
||||
|
||||
boolean prepareSleepMode = false;
|
||||
const String sys_dir = "system";
|
||||
|
||||
const String sleep_sound = "sleep.mp3";
|
||||
|
||||
const String startup_sound = "start.mp3";
|
||||
|
||||
const String mapping_file = "/mapping.txt";
|
||||
const String mapping_file = "mapping.txt";
|
||||
|
||||
const String progress_file = "progress.txt";
|
||||
|
||||
std::map<String, String> rfid_map;
|
||||
|
||||
/*
|
||||
const long sleepMessageDelay = 28000;
|
||||
|
||||
43
src/main.cpp
43
src/main.cpp
@@ -47,14 +47,9 @@
|
||||
#define MAX_VOL 15
|
||||
|
||||
#include "globals.h"
|
||||
#include "WebContent.h"
|
||||
#include "main.h"
|
||||
#include "DirectoryNode.h"
|
||||
|
||||
#define SOUND_STARTUP "start.mp3"
|
||||
#define SOUND_SLEEP "sleep.mp3"
|
||||
|
||||
|
||||
|
||||
|
||||
File root;
|
||||
File mp3File;
|
||||
@@ -280,7 +275,7 @@ void handleDeleteFile(AsyncWebServerRequest *request) {
|
||||
String filename = request->arg("filename");
|
||||
|
||||
if (SD.exists(filename)) {
|
||||
SD.remove(filename.c_str());
|
||||
SD.remove(filename);
|
||||
Serial.println("Deleted file: " + filename);
|
||||
request->send(200, "text/plain", "File deleted successfully.");
|
||||
} else {
|
||||
@@ -492,7 +487,7 @@ String getState()
|
||||
}
|
||||
|
||||
// Function to save the rfid_map to the mapping file
|
||||
void saveMappingToFile(const char *filename) {
|
||||
void saveMappingToFile(const String filename) {
|
||||
File file = SD.open(filename, FILE_WRITE);
|
||||
if (file) {
|
||||
for (const auto &pair : rfid_map) {
|
||||
@@ -511,7 +506,7 @@ void editMapping(AsyncWebServerRequest *request) {
|
||||
String rfid = request->getParam("rfid", true)->value();
|
||||
String song = request->getParam("song", true)->value();
|
||||
rfid_map[rfid] = song;
|
||||
saveMappingToFile(mapping_file.c_str());
|
||||
saveMappingToFile(getSysDir(mapping_file));
|
||||
request->send(200, "text/plain", "Mapping updated");
|
||||
} else {
|
||||
request->send(400, "text/plain", "Invalid parameters");
|
||||
@@ -752,7 +747,7 @@ void setup()
|
||||
|
||||
|
||||
|
||||
String progressPath = "/"+sys_dir+"/"+progress_file;
|
||||
String progressPath = getSysDir(progress_file);
|
||||
|
||||
continuePlaying = readSongProgress(progressPath.c_str());
|
||||
|
||||
@@ -824,14 +819,14 @@ void setup()
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webrequestActive = true;
|
||||
String htmlPath = "/system/index.html";
|
||||
String htmlPath = getSysDir("index.html");
|
||||
if (SD.exists(htmlPath)) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(SD, htmlPath, "text/html", false, processor);
|
||||
response->addHeader("Content-Type", "text/html; charset=UTF-8");
|
||||
request->send(response);
|
||||
} else {
|
||||
// Fallback: serve minimal error if file not found
|
||||
request->send(200, "text/plain", "ERROR: /system/index.html on SD Card not found!");
|
||||
request->send(404, "text/plain", "ERROR: /system/index.html on SD Card not found!");
|
||||
}
|
||||
webrequestActive = false;
|
||||
|
||||
@@ -840,12 +835,12 @@ void setup()
|
||||
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
{
|
||||
webrequestActive = true;
|
||||
String cssPath = "/system/style.css";
|
||||
String cssPath = getSysDir("style.css");
|
||||
if (SD.exists(cssPath)) {
|
||||
request->send(SD, cssPath, "text/css");
|
||||
} else {
|
||||
// Fallback: serve minimal CSS if file not found
|
||||
request->send(200, "text/css", "body{font-family:Arial;text-align:center;padding:20px;}");
|
||||
request->send(404, "text/plain", "ERROR: /system/style.css on SD Card not found!");
|
||||
}
|
||||
webrequestActive = false;
|
||||
|
||||
@@ -856,12 +851,12 @@ void setup()
|
||||
webrequestActive = true;
|
||||
deactivateRFID();
|
||||
activateSD();
|
||||
String jsPath = "/system/script.js";
|
||||
String jsPath = getSysDir("script.js");
|
||||
if (SD.exists(jsPath)) {
|
||||
request->send(SD, jsPath, "application/javascript");
|
||||
} else {
|
||||
// Fallback: serve minimal JS if file not found
|
||||
request->send(200, "application/javascript", "console.log('JavaScript file not found on SD card');");
|
||||
request->send(404, "text/plain", "ERROR: /system/script.js on SD Card not found!");
|
||||
}
|
||||
webrequestActive = false;
|
||||
|
||||
@@ -990,9 +985,9 @@ void volume_action(AsyncWebServerRequest *request)
|
||||
request->send_P(200, "text/plain", "ok");
|
||||
}
|
||||
|
||||
String getStartupSoundDir() {
|
||||
static String tempPath = "/"+sys_dir+"/"+startup_sound;
|
||||
return tempPath;
|
||||
|
||||
const String getSysDir(const String filename) {
|
||||
return "/"+sys_dir+"/"+filename;
|
||||
}
|
||||
|
||||
void loop()
|
||||
@@ -1022,7 +1017,7 @@ void loop()
|
||||
playSongById(currentSongId,currentSongSeconds);
|
||||
} else if (!startupSoundPlayed) {
|
||||
startupSoundPlayed = true;
|
||||
playSongByPath(getStartupSoundDir().c_str());
|
||||
playSongByPath(getSysDir(startup_sound));
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,12 +1029,12 @@ void loop()
|
||||
sleepSoundPlayed = true;
|
||||
prepareSleepMode = true;
|
||||
if (currentNode != NULL) {
|
||||
String progressPath = "/"+sys_dir+"/"+progress_file;
|
||||
String progressPath = getSysDir(progress_file);
|
||||
|
||||
writeSongProgress(progressPath.c_str(),currentNode->getCurrentPlayingId(),currentNode->getSecondsPlayed());
|
||||
}
|
||||
|
||||
String tempPath = "/"+sys_dir+"/"+sleep_sound;
|
||||
String tempPath = getSysDir(sleep_sound);
|
||||
playSongByPath(tempPath.c_str());
|
||||
}
|
||||
|
||||
@@ -1067,7 +1062,7 @@ void loop()
|
||||
vol++;
|
||||
}
|
||||
audio.setVolume(vol);
|
||||
playSongByPath(getStartupSoundDir().c_str());
|
||||
playSongByPath(getSysDir(startup_sound));
|
||||
|
||||
}
|
||||
|
||||
@@ -1083,7 +1078,7 @@ void loop()
|
||||
vol--;
|
||||
}
|
||||
audio.setVolume(vol);
|
||||
playSongByPath(getStartupSoundDir().c_str());
|
||||
playSongByPath(getSysDir(startup_sound));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
85
src/main.h
Normal file
85
src/main.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef MAIN_H_
|
||||
#define MAIN_H_
|
||||
|
||||
void stop();
|
||||
|
||||
void start();
|
||||
|
||||
bool playFile(const char* filename, uint32_t resumeFilePos = 0);
|
||||
|
||||
void loop2(void* parameter);
|
||||
|
||||
void id_song_action(AsyncWebServerRequest *request);
|
||||
|
||||
void progress_action(AsyncWebServerRequest *request);
|
||||
|
||||
void volume_action(AsyncWebServerRequest *request);
|
||||
|
||||
boolean buttonPressed(const uint8_t pin);
|
||||
|
||||
const String getSysDir(const String filename);
|
||||
|
||||
/**
|
||||
* Helper routine to dump a byte array as hex values to Serial.
|
||||
*/
|
||||
void dump_byte_array(byte *buffer, byte bufferSize)
|
||||
{
|
||||
for (byte i = 0; i < bufferSize; i++)
|
||||
{
|
||||
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
|
||||
Serial.print(buffer[i], HEX);
|
||||
}
|
||||
}
|
||||
|
||||
String getRFIDString(byte uidByte[10])
|
||||
{
|
||||
String uidString = String(uidByte[0]) + " " + String(uidByte[1]) + " " +
|
||||
String(uidByte[2]) + " " + String(uidByte[3]);
|
||||
return uidString;
|
||||
}
|
||||
|
||||
void writeFile(fs::FS &fs, const char * path, const char * message){
|
||||
Serial.printf("Writing file: %s\n", path);
|
||||
|
||||
File file = fs.open(path, FILE_WRITE);
|
||||
if(!file){
|
||||
Serial.println("Failed to open file for writing");
|
||||
return;
|
||||
}
|
||||
if(file.print(message)){
|
||||
Serial.println("File written");
|
||||
} else {
|
||||
Serial.println("Write failed");
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
unsigned long lastStart = 0;
|
||||
|
||||
unsigned long lastInteraction = 0;
|
||||
|
||||
boolean sleepSoundPlayed = false;
|
||||
|
||||
boolean startupSoundPlayed = false;
|
||||
|
||||
boolean continuousMode = false;
|
||||
|
||||
uint8_t buttontoignore = 0;
|
||||
|
||||
uint32_t lastVoltage = 0;
|
||||
|
||||
uint loopCounter = 0;
|
||||
|
||||
String lastUid = "";
|
||||
|
||||
uint16_t currentSongId = 0;
|
||||
|
||||
uint32_t currentSongSeconds = 0;
|
||||
|
||||
boolean continuePlaying = false;
|
||||
|
||||
boolean prepareSleepMode = false;
|
||||
|
||||
std::map<String, String> rfid_map;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user