Compare commits

...

9 Commits

8 changed files with 83 additions and 76 deletions

View File

@ -28,7 +28,7 @@ lib_deps = ${extra.lib_deps}
upload_port = /dev/cu.SLAB_USBtoUART upload_port = /dev/cu.SLAB_USBtoUART
monitor_speed = 115200 monitor_speed = 115200
board_build.embed_txtfiles = src/index.html board_build.embed_txtfiles = src/index.html
board_build.partitions = partitions.csv ;board_build.partitions = partitions.csv
;monitor_port = /dev/cu.wchusbserial1420 ;monitor_port = /dev/cu.wchusbserial1420
[env:deploy] [env:deploy]

View File

@ -36,7 +36,6 @@ void Controller::register_http_server(HTTPServer* h) {
} }
void Controller::loop() { void Controller::loop() {
TRACE("Controller::loop()...\n");
unsigned long now = millis(); unsigned long now = millis();
if ((_last_rfid_scan_at < now - RFID_SCAN_INTERVAL) || (now < _last_rfid_scan_at)) { if ((_last_rfid_scan_at < now - RFID_SCAN_INTERVAL) || (now < _last_rfid_scan_at)) {
_check_rfid(); _check_rfid();
@ -66,7 +65,6 @@ void Controller::loop() {
} else { } else {
_last_wifi_try_at = now; _last_wifi_try_at = now;
} }
TRACE("Controller::loop() done.\n");
} }
uint32_t Controller::_get_rfid_card_uid() { uint32_t Controller::_get_rfid_card_uid() {
@ -85,7 +83,7 @@ uint32_t Controller::_get_rfid_card_uid() {
} }
void Controller::_check_rfid() { void Controller::_check_rfid() {
TRACE("check_rfid running...\n"); //TRACE("check_rfid running...\n");
MFRC522::StatusCode status; MFRC522::StatusCode status;
if (_rfid_present) { if (_rfid_present) {
byte buffer[2]; byte buffer[2];
@ -144,7 +142,8 @@ void Controller::_check_rfid() {
if (time.tm_mon == 11) { // tm_mon is "months since january", so 11 means december. if (time.tm_mon == 11) { // tm_mon is "months since january", so 11 means december.
pl->advent_shuffle(time.tm_mday); pl->advent_shuffle(time.tm_mday);
} else { } else {
// TODO DEBUG("Album is in advent mode, but it isn't december (yet). Not playing.\n");
return;
} }
} else if (data.indexOf("[random]") != -1 && pl->is_fresh()) { } else if (data.indexOf("[random]") != -1 && pl->is_fresh()) {
pl->shuffle(); pl->shuffle();
@ -200,7 +199,7 @@ String Controller::_read_rfid_data() {
case MFRC522::PICC_TYPE_MIFARE_4K: sectors = 40; break; case MFRC522::PICC_TYPE_MIFARE_4K: sectors = 40; break;
default: INFO("Unknown PICC type %s\n", String(MFRC522::PICC_GetTypeName(type)).c_str()); default: INFO("Unknown PICC type %s\n", String(MFRC522::PICC_GetTypeName(type)).c_str());
} }
sectors = 2; // Pretend we have only two sectors, so we read only sector #1.
int good_key_index = -1; int good_key_index = -1;
for (uint8_t sector=1; sector<sectors; sector++) { for (uint8_t sector=1; sector<sectors; sector++) {
uint8_t blocks = (sector < 32) ? 4 : 16; uint8_t blocks = (sector < 32) ? 4 : 16;
@ -244,8 +243,6 @@ String Controller::_read_rfid_data() {
} }
void Controller::_check_serial() { void Controller::_check_serial() {
TRACE("check_serial running...\n");
if (Serial.available() > 0) { if (Serial.available() > 0) {
char c = Serial.read(); char c = Serial.read();
Serial.printf("%c", c); Serial.printf("%c", c);
@ -332,8 +329,6 @@ void Controller::_execute_command_help() {
} }
void Controller::_check_buttons() { void Controller::_check_buttons() {
TRACE("check_buttons running...\n");
if (BTN_PREV() && _debounce_button(0)) { if (BTN_PREV() && _debounce_button(0)) {
if (_state == NORMAL) { if (_state == NORMAL) {
player->track_prev(); player->track_prev();

View File

@ -72,6 +72,9 @@ bool HTTPClientWrapper::_request(String method, String url, uint32_t offset, uin
DEBUG("Unexpected HTTP return code %d. Cancelling.\n", status); DEBUG("Unexpected HTTP return code %d. Cancelling.\n", status);
return false; return false;
} }
_buffer_position = 0;
_buffer_length = 0;
_connected = true; _connected = true;
_length = _http->getSize() + offset; _length = _http->getSize() + offset;

View File

@ -188,7 +188,7 @@ update_playlist = function(data) {
tr = $('<tr>').data('track', i); tr = $('<tr>').data('track', i);
tr.append($('<td>').html(i + 1)); tr.append($('<td>').html(i + 1));
tr.append($('<td>').html(data.current_track==i ? '<i class="fa fa-play"></i>' : '')); tr.append($('<td>').html(data.current_track==i ? '<i class="fa fa-play"></i>' : ''));
tr.append($('<td>').html(data.files[i].substr(data.files[i].title))); tr.append($('<td>').html(data.files[i].title));
$('#track_list').append(tr); $('#track_list').append(tr);
} }

View File

@ -2,6 +2,7 @@
#include <SPI.h> #include <SPI.h>
#include <SD.h> #include <SD.h>
#include <WiFi.h> #include <WiFi.h>
#include <WiFiMulti.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include "main.h" #include "main.h"
#include "config.h" #include "config.h"
@ -19,34 +20,22 @@ HTTPServer* http_server;
uint8_t SPIMaster::state = 0; uint8_t SPIMaster::state = 0;
bool connect_to_wifi(String ssid, String pass) {
TRACE("Connecting to wifi \"%s\"...\n", ssid.c_str());
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid.c_str(), pass.c_str());
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
DEBUG("Could not connect to wifi \"%s\".\n", ssid.c_str());
return false;
} else {
INFO("Connected to \"%s\". IP address: %s\n", ssid.c_str(), WiFi.localIP().toString().c_str());
}
return true;
}
void wifi_connect() { void wifi_connect() {
bool connected = false;
INFO("Connecting to WiFi...\n"); INFO("Connecting to WiFi...\n");
WiFiMulti wifi;
SPIMaster::select_sd(); SPIMaster::select_sd();
if (SD.exists("/_wifis.txt")) { if (SD.exists("/_wifis.txt")) {
DEBUG("Reading /_wifis.txt\n"); DEBUG("Reading /_wifis.txt\n");
File f = SD.open("/_wifis.txt", "r"); File f = SD.open("/_wifis.txt", "r");
while (String line = f.readStringUntil('\n')) { while (String line = f.readStringUntil('\n')) {
if (line.length()==0 || line.startsWith("#") || line.indexOf('=')==-1) { if (line.length()==0) {
break;
} else if (line.startsWith("#") || line.indexOf('=')==-1) {
continue; continue;
} }
String ssid = line.substring(0, line.indexOf('=')); String ssid = line.substring(0, line.indexOf('='));
String pass = line.substring(line.indexOf('=')+1); String pass = line.substring(line.indexOf('=')+1);
connected = connect_to_wifi(ssid, pass); wifi.addAP(ssid.c_str(), pass.c_str());
if (connected) break;
} }
f.close(); f.close();
} else { } else {
@ -55,22 +44,21 @@ void wifi_connect() {
f.close(); f.close();
} }
SPIMaster::select_sd(false); SPIMaster::select_sd(false);
if (!connected) { #if defined(WIFI_SSID) and defined(WIFI_PASS)
#if defined(WIFI_SSID) and defined(WIFI_PASS) wifi.addAP(WIFI_SSID, WIFI_PASS);
DEBUG("Trying hardcoded WiFi data...\n"); #endif
connected = connect_to_wifi(WIFI_SSID, WIFI_PASS);
#else if (wifi.run() == WL_CONNECTED) {
DEBUG("No hardcoded WiFi data set.\n"); DEBUG("Connected to WiFi \"%s\".\n", WiFi.SSID().c_str());
#endif } else {
} DEBUG("No WiFi connection!\n");
if (!connected) {
INFO("No WiFi connection!\n");
} }
} }
void setup() { void setup() {
delay(500); // Small delay to give the Serial console a bit of time to connect.
delay(1000);
Serial.begin(115200); Serial.begin(115200);
Serial.println("Starting..."); Serial.println("Starting...");
Serial.println("Started."); Serial.println("Started.");
@ -125,6 +113,12 @@ void setup() {
} else { } else {
INFO("Could not fetch current time via NTP.\n"); INFO("Could not fetch current time via NTP.\n");
} }
#ifdef VERSION
INFO("ESMP3 version %s (OTA_VERSION %d)\n", VERSION, OTA_VERSION);
#else
INFO("ESMP3, version unknown (OTA_VERSION %d)\n", OTA_VERSION);
#endif
INFO("Initialization completed.\n"); INFO("Initialization completed.\n");
} }

View File

@ -464,14 +464,14 @@ void Player::set_volume(uint8_t vol, bool save) {
void Player::vol_up() { void Player::vol_up() {
if (!is_playing()) return; if (!is_playing()) return;
uint8_t vol = _volume + VOLUME_STEP; uint16_t vol = _volume + VOLUME_STEP;
if (vol > VOLUME_MAX) vol=VOLUME_MAX; if (vol > VOLUME_MAX) vol=VOLUME_MAX;
set_volume(vol); set_volume(vol);
} }
void Player::vol_down() { void Player::vol_down() {
if (!is_playing()) return; if (!is_playing()) return;
uint8_t vol = _volume - VOLUME_STEP; int16_t vol = _volume - VOLUME_STEP;
if (vol < VOLUME_MIN) vol=VOLUME_MIN; if (vol < VOLUME_MIN) vol=VOLUME_MIN;
set_volume(vol); set_volume(vol);
} }

View File

@ -135,6 +135,7 @@ void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t
xml_enclosure_url = ""; xml_enclosure_url = "";
} else if (tag.endsWith("/item") && (status & STATUS_END_TAG)) { } else if (tag.endsWith("/item") && (status & STATUS_END_TAG)) {
if (xml_title.length()>0 && xml_url.length()>0) { if (xml_title.length()>0 && xml_url.length()>0) {
if (xml_files_ptr->size() > 20) return;
DEBUG("Adding playlist entry: '%s' => '%s'\n", xml_title.c_str(), xml_url.c_str()); DEBUG("Adding playlist entry: '%s' => '%s'\n", xml_title.c_str(), xml_url.c_str());
xml_files_ptr->insert(xml_files_ptr->begin(), {.filename=xml_url, .title=xml_title, .id=xml_guid}); xml_files_ptr->insert(xml_files_ptr->begin(), {.filename=xml_url, .title=xml_title, .id=xml_guid});
} }
@ -158,6 +159,7 @@ void Playlist::_parse_rss(HTTPClientWrapper* http) {
while ((i = http->read()) >= 0) { while ((i = http->read()) >= 0) {
xml.processChar(i); xml.processChar(i);
} }
_current_track = _files.size()-1;
xml_files_ptr = NULL; xml_files_ptr = NULL;
if (xml_album_title.length()>0) { if (xml_album_title.length()>0) {
_title = xml_album_title; _title = xml_album_title;
@ -317,12 +319,19 @@ void Playlist::shuffle(uint8_t random_offset) {
} }
void Playlist::advent_shuffle(uint8_t day) { void Playlist::advent_shuffle(uint8_t day) {
if (day > 24) day = 24; TRACE("advent_shuffle running...\n");
if (day > _files.size()) return; // Not enough songs till the current day? Play all songs in the default order.
if (day > _files.size()) {
return;
}
// We are in the "different playlist every day" mode. So we don't persist it in order to not miss changes.
persistence = PERSIST_NONE;
_files.insert(_files.begin(), _files[day - 1]); _files.insert(_files.begin(), _files[day - 1]);
_files.erase(_files.begin() + day - 1, _files.end()); _files.erase(_files.begin() + day, _files.end());
} }
void Playlist::reset() { void Playlist::reset() {
@ -375,6 +384,7 @@ void Playlist::json(JsonObject json) {
JsonObject o = files.createNestedObject(); JsonObject o = files.createNestedObject();
o["filename"] = entry.filename; o["filename"] = entry.filename;
o["title"] = entry.title; o["title"] = entry.title;
o["id"] = entry.id;
} }
json["current_track"] = _current_track; json["current_track"] = _current_track;
json["has_track_next"] = has_track_next(); json["has_track_next"] = has_track_next();

View File

@ -109,7 +109,6 @@ Playlist* PlaylistManager::get_playlist_for_folder(String folder) {
p = new Playlist(folder); p = new Playlist(folder);
_playlists[folder] = p; _playlists[folder] = p;
if (p->persistence == PERSIST_PERMANENTLY) { if (p->persistence == PERSIST_PERMANENTLY) {
// TODO Load persistence from file
String search = folder; String search = folder;
search += "="; search += "=";
SPIMaster::select_sd(); SPIMaster::select_sd();
@ -197,38 +196,44 @@ String PlaylistManager::create_mapping_txt() {
} }
void PlaylistManager::persist(Playlist* p) { void PlaylistManager::persist(Playlist* p) {
if (p->persistence != PERSIST_PERMANENTLY) return; if (p->persistence == PERSIST_NONE) {
_playlists.erase(p->path());
return;
} else if (p->persistence == PERSIST_PERMANENTLY) {
String search = p->path(); String search = p->path();
search += '='; search += '=';
bool old_file_existed = false; bool old_file_existed = false;
SPIMaster::select_sd(); SPIMaster::select_sd();
if (SD.exists("_positions.txt")) { if (SD.exists("_positions.txt")) {
SD.rename("/_positions.txt", "/_positions.temp.txt"); SD.rename("/_positions.txt", "/_positions.temp.txt");
old_file_existed = true; old_file_existed = true;
} }
File dst = SD.open("/_positions.txt", "w"); File dst = SD.open("/_positions.txt", "w");
if (old_file_existed) { if (old_file_existed) {
File src = SD.open("/_positions.temp.txt", "r"); File src = SD.open("/_positions.temp.txt", "r");
while (true) { while (true) {
String line = src.readStringUntil('\n'); String line = src.readStringUntil('\n');
line.trim(); line.trim();
if (line.startsWith(search)) continue; if (line.startsWith(search)) continue;
dst.println(line); dst.println(line);
}
src.close();
SD.remove("/_positions.temp.txt");
} }
src.close(); dst.print(search);
SD.remove("/_positions.temp.txt"); dst.print(p->get_current_track_id());
dst.print(',');
dst.println(p->get_position());
dst.close();
SPIMaster::select_sd(false);
_playlists.erase(p->path());
} }
dst.print(search);
dst.print(p->get_current_track_id());
dst.print(',');
dst.println(p->get_position());
dst.close();
SPIMaster::select_sd(false);
} }