Browse Source

Improved localization + FTP is disabled after boot as per default

master
Torsten Stauder 5 years ago
parent
commit
f4a2a95e5f
  1. 11
      README.md
  2. 4
      src/logmessages.h
  3. 4
      src/logmessages_EN.h
  4. 126
      src/main.cpp
  5. 2
      src/settings.h

11
README.md

@ -11,7 +11,7 @@ Finally, the long announced Tonuino-PCB for Wemos' Lolin32 is [there](https://gi
* 01.11.2020: Added directive `SD_NOT_MANDATORY_ENABLE`: for debugging puposes SD can be bypassed at boot.
* 17.11.2020: Introduced a distinct volume for headphone for optional headphone-PCB.
* 20.11.2020: Added directive `MEASURE_BATTERY_VOLTAGE`: monitoring battery's voltage is now supported.
* 25.11.2020: WiFi can npw be activated/deactivated instantly by pressing two buttons.
* 25.11.2020: WiFi can now be enabled/disabled instantly by pressing two buttons.
* 28.11.2020: Battery's voltage can now be visualized by Neopixel by short-press of rotary encoder's burtton.
* 28.11.2020: Added directive `PLAY_LAST_RFID_AFTER_REBOOT`: Tonuino will recall the last RFID played after reboot.
* 05.12.2020: Added filebrowser to webgui (thanks @mariolukas for contribution!)
@ -22,6 +22,7 @@ Finally, the long announced Tonuino-PCB for Wemos' Lolin32 is [there](https://gi
* 11.12.2020: Revised GUI-design (thanks @mariolukas for contribution!) + (untested) PCB added for Wemos Lolin D32 + gerberfiles for headphone-PCB
* 18.12.2020: Added SD-MMC 1 Bit-mode (`SD_MMC_1BIT_MODE`). This mode needs one GPIO less and provides almost doubled speed (compared to SPI) for FTP-transfers (thanks @tueddy for contribution!)
* 18.12.2020: Added support for RFID-reader PN5180 (`RFID_READER_TYPE_PN5180`). PN5180 has better RFID-range/sensitivity and can read ISO-15693 / iCode SLIX2-tags aka 'Tonies' (thanks @tueddy for contribution!)
* 20.12.2020: Due to memory-issues with webstreams, FTP needs to be activated by pressing pause+next-button now
<br />More to come...
## Known bugs
@ -355,7 +356,13 @@ After having Tonuino running on your ESP32 in your local WiFi, the webinterface-
* General-configuration (volume (speaker + headphone), neopixel-brightness (night-mode + initial), sleep after inactivity)
### FTP (optional)
In order to avoid exposing uSD-card or disassembling the Tonuino all the time for adding new music, it's possible to transfer music onto the uSD-card using FTP. Please make sure to set the max. number of parallel connections to ONE in your FTP-client. My recommendation is [Filezilla](https://filezilla-project.org/). But don't expect fast data-transfer. Initially it was around 145 kB/s but after modifying ftp-server-lib (changing from 4 kB static-buffer to 16 kB heap-buffer) I saw rates improving to around 185 kB/s. Please note: if music is played in parallel, this rate decrases dramatically! So better stop playback when doing a FTP-transfer. However, playback sounds normal if a FTP-upload is performed in parallel. Default-user and password are set to `esp32` / `esp32` but can be changed later via GUI.
* In order to avoid exposing uSD-card or disassembling Tonuino all the time for adding new music, it's possible to transfer music to the uSD-card using FTP.
* Default-user and password are set to `esp32` / `esp32` but can be changed later via GUI.
* FTP needs to be activated after boot by pressing `PAUSE` + `NEXT`-buttons (in parallel) first! Neopixel flashes green (1x) if enabling was successful.
* Make sure to set the max. number of parallel connections to ONE in your FTP-client.
* Software: my recommendation is [Filezilla](https://filezilla-project.org/).
* Don't expect a super fast data-transfer; it's around 180 kB/s (SPI-mode) and >=300 kB/s (MMC-mode).
* Please note: if music is played in parallel, this rate decrases dramatically! So better stop playback when doing a FTP-transfer.
### Files / ID3-tags (IMPORTANT!)
Make sure to not use filenames that contain German 'Umlaute'. I've been told this is also true for mp3's ID3-tags. Also better remove coverarts from the files.

4
src/logmessages.h

@ -18,7 +18,7 @@ static const char freeMemory[] PROGMEM = "Freier Speicher";
static const char writeEntryToNvs[] PROGMEM = "Schreibe Eintrag in NVS";
static const char freeMemoryAfterFree[] PROGMEM = "Freier Speicher nach Aufräumen";
static const char releaseMemoryOfOldPlaylist[] PROGMEM = "Gebe Speicher der alten Playlist frei.";
static const char dirOrFileDoesNotExist[] PROGMEM = "Datei oder Verzeichnis existiert nicht!";
static const char dirOrFileDoesNotExist[] PROGMEM = "Datei oder Verzeichnis existiert nicht ";
static const char unableToAllocateMemForPlaylist[] PROGMEM = "Speicher für Playlist konnte nicht allokiert werden!";
static const char unableToAllocateMem[] PROGMEM = "Speicher konnte nicht allokiert werden!";
static const char fileModeDetected[] PROGMEM = "Dateimodus erkannt.";
@ -164,3 +164,5 @@ static const char sdMountedMmc1BitMode[] PROGMEM = "Versuche SD-Karte wird im SD
static const char sdMountedSpiMode[] PROGMEM = "Versuche SD-Karte wird im SPI-Modus zu mounten...";
static const char backupRecoveryWebsite[] PROGMEM = "<p>Das Backup-File wird eingespielt...<br />Zur letzten Seite <a href=\"javascript:history.back()\">zur&uuml;ckkehren</a>.</p>";
static const char restartWebsite[] PROGMEM = "<p>Der Tonuino wird neu gestartet...<br />Zur letzten Seite <a href=\"javascript:history.back()\">zur&uuml;ckkehren</a>.</p>";
static const char mqttMsgReceived[] PROGMEM = "MQTT-Nachricht empfangen";
static const char trackPausedAtPos[] PROGMEM = "Titel pausiert bei Position";

4
src/logmessages_EN.h

@ -18,7 +18,7 @@ static const char freeMemory[] PROGMEM = "Free memory";
static const char writeEntryToNvs[] PROGMEM = "Storing data to NVS";
static const char freeMemoryAfterFree[] PROGMEM = "Free memory after cleaning";
static const char releaseMemoryOfOldPlaylist[] PROGMEM = "Releasing memory of old playlist.";
static const char dirOrFileDoesNotExist[] PROGMEM = "File of directory does not exist!";
static const char dirOrFileDoesNotExist[] PROGMEM = "File of directory does not exist";
static const char unableToAllocateMemForPlaylist[] PROGMEM = "Unable to allocate memory for playlist!";
static const char unableToAllocateMem[] PROGMEM = "Unable to allocate memory!";
static const char fileModeDetected[] PROGMEM = "File-mode detected.";
@ -164,3 +164,5 @@ static const char sdMountedMmc1Bit[] PROGMEM = "SD-card in SD_MMC 1 Bit-mode con
static const char sdMountedSpiMode[] PROGMEM = "SD card mounted in SPI-mode configured...";
static const char backupRecoveryWebsite[] PROGMEM = "<p>Backup-file is being applied...<br />Back to <a href=\"javascript:history.back()\">last page</a>.</p>";
static const char restartWebsite[] PROGMEM = "<p>Tonuino is being restarted...<br />Back to <a href=\"javascript:history.back()\">last page</a>.</p>";
static const char mqttMsgReceived[] PROGMEM = "MQTT-message received";
static const char trackPausedAtPos[] PROGMEM = "Track paused at position";

126
src/main.cpp

@ -269,6 +269,8 @@ TaskHandle_t rfid;
// FTP
#ifdef FTP_ENABLE
FtpServer ftpSrv;
bool ftpEnableLastStatus = false;
bool ftpEnableCurrentStatus = false;
#endif
// Info: SSID / password are stored in NVS
@ -420,29 +422,20 @@ void IRAM_ATTR onTimer() {
}
#endif
/**
* Creates a new file on the SD Card.
* @param fs
* @param path
* @param message
*/
// Creates a new file on the SD-card.
void createFile(fs::FS &fs, const char * path, const char * message) {
//snprintf(logBuf, serialLoglength, "Writing file: %s\n", path);
snprintf(logBuf, serialLoglength, "%s: %s", (char *) FPSTR(writingFile), path);
loggerNl(logBuf, LOGLEVEL_DEBUG);
File file = fs.open(path, FILE_WRITE);
if (!file) {
snprintf(logBuf, serialLoglength, "%s", (char *) FPSTR(failedOpenFileForWrite));
//snprintf(logBuf, serialLoglength, "Failed to open file for writing");
loggerNl(logBuf, LOGLEVEL_ERROR);
return;
}
if (file.print(message)) {
//snprintf(logBuf, serialLoglength, "File written");
snprintf(logBuf, serialLoglength, "%s", (char *) FPSTR(fileWritten));
loggerNl(logBuf, LOGLEVEL_DEBUG);
} else {
//snprintf(logBuf, serialLoglength, "Write failed");
snprintf(logBuf, serialLoglength, "%s", (char *) FPSTR(writeFailed));
loggerNl(logBuf, LOGLEVEL_ERROR);
}
@ -454,14 +447,7 @@ bool fileExists(fs::FS &fs, const char *file) {
return fs.exists(file);
}
/**
* Appends raw input to a file
* @param fs
* @param path
* @param text
*/
// Appends raw input to a file
void appendToFile(fs::FS &fs, const char *path, const char *text) {
File file = fs.open(path, FILE_APPEND);
esp_task_wdt_reset();
@ -513,7 +499,7 @@ void appendNodeToJSONFile(fs::FS &fs, const char * path, const char *filename, c
}
}
// Checks if a path is valid. (e.g. hidden path is not valid)
// Checks if a path is valid. (e.g. hidden path is not valid)
bool pathValid(const char *_fileItem) {
const char ch = '/';
char *subst;
@ -688,6 +674,19 @@ void doButtonActions(void) {
return;
}
// FTP-enable
#ifdef FTP_ENABLE
if (!ftpEnableLastStatus && !ftpEnableCurrentStatus) {
if (buttons[0].isPressed && buttons[2].isPressed) {
ftpEnableLastStatus = true;
#ifdef NEOPIXEL_ENABLE
showLedOk = true;
#endif
}
}
return;
#endif
for (uint8_t i=0; i < sizeof(buttons) / sizeof(buttons[0]); i++) {
if (buttons[i].isPressed) {
if (buttons[i].lastReleasedTimestamp > buttons[i].lastPressedTimestamp) {
@ -884,7 +883,7 @@ void callback(const char *topic, const byte *payload, uint32_t length) {
char *receivedString = strndup((char*)payload, length);
char *mqttTopic = strdup(topic);
snprintf(logBuf, serialLoglength, "MQTT-Nachricht empfangen: [Topic: %s] [Kommando: %s]", mqttTopic, receivedString);
snprintf(logBuf, serialLoglength, "%s: [Topic: %s] [Command: %s]", (char *) FPSTR(mqttMsgReceived), mqttTopic, receivedString);
loggerNl(logBuf, LOGLEVEL_INFO);
// Go to sleep?
@ -1324,7 +1323,7 @@ char ** returnPlaylistFromSD(File _fileOrDirectory) {
snprintf(logBuf, serialLoglength, "%s: %d", (char *) FPSTR(numberOfValidFiles), cnt);
loggerNl(logBuf, LOGLEVEL_NOTICE);
return ++files; // return ptr+1 (starting at 1st payload-item)
return ++files; // return ptr+1 (starting at 1st payload-item); ptr+0 contains number of items
}
@ -1352,7 +1351,11 @@ size_t nvsRfidWriteWrapper (const char *_rfidCardId, const char *_track, const u
}
snprintf(prefBuf, sizeof(prefBuf) / sizeof(prefBuf[0]), "%s%s%s%u%s%d%s%u", stringDelimiter, trackBuf, stringDelimiter, _playPosition, stringDelimiter, _playMode, stringDelimiter, _trackLastPlayed);
snprintf(logBuf, serialLoglength, "Schreibe '%s' in NVS für RFID-Card-ID %s mit playmode %d und letzter Track %u\n", prefBuf, _rfidCardId, _playMode, _trackLastPlayed);
#if (LANGUAGE == 1)
snprintf(logBuf, serialLoglength, "Schreibe '%s' in NVS für RFID-Card-ID %s mit playmode %d und letzter Track %u\n", prefBuf, _rfidCardId, _playMode, _trackLastPlayed);
#else
snprintf(logBuf, serialLoglength, "Write '%s' to NVS for RFID-Card-ID %s with playmode %d and last track %u\n", prefBuf, _rfidCardId, _playMode, _trackLastPlayed);
#endif
logger(logBuf, LOGLEVEL_INFO);
loggerNl(prefBuf, LOGLEVEL_INFO);
#ifdef NEOPIXEL_ENABLE
@ -1394,7 +1397,11 @@ void playAudio(void *parameter) {
playProperties.pausePlay = !playProperties.pausePlay;
}
audio.stopSong();
snprintf(logBuf, serialLoglength, "%s mit %d Titel(n)", (char *) FPSTR(newPlaylistReceived), playProperties.numberOfTracks);
#if (LANGUAGE == 1)
snprintf(logBuf, serialLoglength, "%s mit %d Titel(n)", (char *) FPSTR(newPlaylistReceived), playProperties.numberOfTracks);
#else
snprintf(logBuf, serialLoglength, "%s with %d track(s)", (char *) FPSTR(newPlaylistReceived), playProperties.numberOfTracks);
#endif
loggerNl(logBuf, LOGLEVEL_NOTICE);
Serial.print(F("Free heap: "));
Serial.println(ESP.getFreeHeap());
@ -1454,7 +1461,7 @@ void playAudio(void *parameter) {
trackCommand = 0;
loggerNl((char *) FPSTR(cmndPause), LOGLEVEL_INFO);
if (playProperties.saveLastPlayPosition && !playProperties.pausePlay) {
snprintf(logBuf, serialLoglength, "Titel wurde bei Position %u pausiert.", audio.getFilePos());
snprintf(logBuf, serialLoglength, "%s: %u", FPSTR(trackPausedAtPos), audio.getFilePos());
loggerNl(logBuf, LOGLEVEL_INFO);
nvsRfidWriteWrapper(playProperties.playRfidTag, *(playProperties.playlist + playProperties.currentTrackNumber), audio.getFilePos(), playProperties.playMode, playProperties.currentTrackNumber, playProperties.numberOfTracks);
}
@ -1625,7 +1632,11 @@ void playAudio(void *parameter) {
nvsRfidWriteWrapper(playProperties.playRfidTag, *(playProperties.playlist + 0), 0, playProperties.playMode, 0, playProperties.numberOfTracks);
}
#ifdef MQTT_ENABLE
publishMqtt((char *) FPSTR(topicTrackState), "<Ende>", false);
#if (LANGUAGE == 1)
publishMqtt((char *) FPSTR(topicTrackState), "<Ende>", false);
#else
publishMqtt((char *) FPSTR(topicTrackState), "<End>", false);
#endif
#endif
playProperties.playlistFinished = true;
playProperties.playMode = NO_PLAYLIST;
@ -1659,7 +1670,7 @@ void playAudio(void *parameter) {
} else {
// Files from SD
if (!FSystem.exists(*(playProperties.playlist + playProperties.currentTrackNumber))) { // Check first if file/folder exists
snprintf(logBuf, serialLoglength, "Datei/Ordner '%s' existiert nicht", *(playProperties.playlist + playProperties.currentTrackNumber));
snprintf(logBuf, serialLoglength, "%s: %s", (char *) FPSTR(dirOrFileDoesNotExist), *(playProperties.playlist + playProperties.currentTrackNumber));
loggerNl(logBuf, LOGLEVEL_ERROR);
playProperties.trackFinished = true;
continue;
@ -1678,7 +1689,11 @@ void playAudio(void *parameter) {
#ifdef MQTT_ENABLE
publishMqtt((char *) FPSTR(topicTrackState), buf, false);
#endif
snprintf(logBuf, serialLoglength, "'%s' wird abgespielt (%d von %d)", *(playProperties.playlist + playProperties.currentTrackNumber), (playProperties.currentTrackNumber+1) , playProperties.numberOfTracks);
#if (LANGUAGE == 1)
snprintf(logBuf, serialLoglength, "'%s' wird abgespielt (%d von %d)", *(playProperties.playlist + playProperties.currentTrackNumber), (playProperties.currentTrackNumber+1) , playProperties.numberOfTracks);
#else
snprintf(logBuf, serialLoglength, "'%s' is being played (%d of %d)", *(playProperties.playlist + playProperties.currentTrackNumber), (playProperties.currentTrackNumber+1) , playProperties.numberOfTracks);
#endif
loggerNl(logBuf, LOGLEVEL_NOTICE);
playProperties.playlistFinished = false;
}
@ -1931,12 +1946,6 @@ void showLed(void *parameter) {
continue;
}
#endif
/*#ifdef FTP_ENABLE
if (ftpSrv.isConnected()) { // Workaround: after moving Neopixel's task to 2nd cpu-core, FTP-transfer-rate decreased. By disabling Neopixel-animation, this can be rescued a bit
vTaskDelay(portTICK_RATE_MS*100);
continue;
}
#endif*/
if (!bootComplete) { // Rotates orange unless boot isn't complete
FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) {
@ -3009,7 +3018,11 @@ void accessPointStart(const char *SSID, IPAddress ip, IPAddress netmask) {
});
wServer.on("/restart", HTTP_GET, [] (AsyncWebServerRequest *request) {
request->send(200, "text/html", "ESP wird neu gestartet...");
#if (LANGUAGE == 1)
request->send(200, "text/html", "ESP wird neu gestartet...");
#else
request->send(200, "text/html", "ESP is being restarted...");
#endif
Serial.flush();
ESP.restart();
});
@ -3061,6 +3074,16 @@ bool writeWifiStatusToNVS(bool wifiStatus) {
}
#ifdef FTP_ENABLE
void ftpManager(void) {
if (ftpEnableLastStatus && !ftpEnableCurrentStatus) {
ftpEnableCurrentStatus = true;
ftpSrv.begin(FSystem, ftpUser, ftpPassword);
Serial.println("FTP aktiviert");
}
}
#endif
// Provides management for WiFi
wl_status_t wifiManager(void) {
// If wifi whould not be activated, return instantly
@ -3107,11 +3130,12 @@ wl_status_t wifiManager(void) {
if (WiFi.status() == WL_CONNECTED) {
myIP = WiFi.localIP();
snprintf(logBuf, serialLoglength, "Aktuelle IP: %d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
loggerNl(logBuf, LOGLEVEL_NOTICE);
#ifdef FTP_ENABLE
ftpSrv.begin(FSystem, ftpUser, ftpPassword);
#if (LANGUAGE == 1)
snprintf(logBuf, serialLoglength, "Aktuelle IP: %d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
#else
snprintf(logBuf, serialLoglength, "Current IP: %d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
#endif
loggerNl(logBuf, LOGLEVEL_NOTICE);
} else { // Starts AP if WiFi-connect wasn't successful
accessPointStart((char *) FPSTR(accessPointNetworkSSID), apIP, apNetmask);
}
@ -3200,7 +3224,11 @@ bool processJsonRequest(char *_serialJson) {
JsonObject object = doc.as<JsonObject>();
if (error) {
Serial.print(F("deserializeJson() failed: "));
#if (LANGUAGE == 1)
Serial.print(F("deserializeJson() fehlgeschlagen: "));
#else
Serial.print(F("deserializeJson() failed: "));
#endif
Serial.println(error.c_str());
return false;
}
@ -3664,7 +3692,6 @@ void setup() {
NULL, /* Task input parameter */
1 | portPRIVILEGE_BIT, /* Priority of the task */
&LED, /* Task handle. */
// 1 /* Core where the task should run */
0 /* Core where the task should run */
);
#endif
@ -3687,10 +3714,10 @@ void setup() {
#endif
#ifndef SINGLE_SPI_ENABLE
#ifdef SD_MMC_1BIT_MODE
while (!SD_MMC.begin("/sdcard", true)) {
#ifdef SD_MMC_1BIT_MODE
while (!SD_MMC.begin("/sdcard", true)) {
#else
while (!SD.begin(SPISD_CS, spiSD)) {
while (!SD.begin(SPISD_CS, spiSD)) {
#endif
#else
while (!SD.begin(SPISD_CS)) {
@ -3712,7 +3739,7 @@ void setup() {
Serial.println(F("|_ _|___ ___| | | | | | | "));
Serial.println(F(" | | | . | | | |- -| | | | | | "));
Serial.println(F(" |_| |___|_|_|_____|_____|_|___|_____| "));
Serial.println(F(" ESP-32 version"));
Serial.println(F(" ESP32-version"));
Serial.println(F(""));
// show SD card type
@ -4029,6 +4056,7 @@ void setup() {
void loop() {
webserverStart();
ftpManager();
#ifdef HEADPHONE_ADJUST_ENABLE
headphoneVolumeManager();
#endif
@ -4050,12 +4078,16 @@ void loop() {
}
#endif
#ifdef FTP_ENABLE
ftpSrv.handleFTP();
if (ftpEnableLastStatus && ftpEnableCurrentStatus) {
ftpSrv.handleFTP();
}
#endif
}
#ifdef FTP_ENABLE
if (ftpSrv.isConnected()) {
lastTimeActiveTimestamp = millis(); // Re-adjust timer while client is connected to avoid ESP falling asleep
if (ftpEnableLastStatus && ftpEnableCurrentStatus) {
if (ftpSrv.isConnected()) {
lastTimeActiveTimestamp = millis(); // Re-adjust timer while client is connected to avoid ESP falling asleep
}
}
#endif
#ifdef PLAY_LAST_RFID_AFTER_REBOOT

2
src/settings.h

@ -3,7 +3,7 @@
//########################## MODULES #################################
#define MDNS_ENABLE // When enabled, you don't have to handle with Tonuino's IP-address. If hostname is set to "tonuino", you can reach it via tonuino.local
#define MQTT_ENABLE // Make sure to configure mqtt-server and (optionally) username+pwd
#define FTP_ENABLE // Enables FTP-server
#define FTP_ENABLE // Enables FTP-server; DON'T FORGET TO ACTIVATE AFTER BOOT BY PRESSING PAUSE + NEXT-BUTTONS (IN PARALLEL)!
#define NEOPIXEL_ENABLE // Don't forget configuration of NUM_LEDS if enabled
#define NEOPIXEL_REVERSE_ROTATION // Some Neopixels are adressed/soldered counter-clockwise. This can be configured here.
#define LANGUAGE 1 // 1 = deutsch; 2 = english

Loading…
Cancel
Save