Compare commits

...

6 Commits

7 changed files with 94 additions and 17 deletions

View File

@ -170,3 +170,5 @@ PLS files, M3U files or podcast XML feeds are supported). |
| `add_mapping=<ID>=<PATH>` | Adds a mapping between RFID card <ID> and path | `add_mapping=<ID>=<PATH>` | Adds a mapping between RFID card <ID> and path
<PATH>. See `play` for valid path formats. | <PATH>. See `play` for valid path formats. |
| `update` | Runs an update check. | | `update` | Runs an update check. |
| `debug=<0|1>` | Enables / disables debug messages. This value is persisted across reboots. |
| `trace=<0|1>` | Enables / disables tracing messages. This value is also persisted across reboots. |

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include <Preferences.h>
void wifi_connect(); void wifi_connect();
extern const uint8_t file_index_html_start[] asm("_binary_src_index_html_start"); extern const uint8_t file_index_html_start[] asm("_binary_src_index_html_start");
extern bool debug_enabled;
extern bool trace_enabled;
extern Preferences prefs;

View File

@ -301,6 +301,24 @@ bool Controller::process_message(String cmd) {
} else if (cmd.equals("update")) { } else if (cmd.equals("update")) {
Updater::run(); Updater::run();
#endif #endif
} else if (cmd.startsWith("trace=")) {
int val = cmd.substring(6).toInt();
if (val==0) {
trace_enabled = false;
prefs.putBool("trace_enabled", false);
} else if (val==1) {
trace_enabled = true;
prefs.putBool("trace_enabled", true);
}
} else if (cmd.startsWith("debug=")) {
int val = cmd.substring(6).toInt();
if (val==0) {
debug_enabled = false;
prefs.putBool("debug_enabled", false);
} else if (val==1) {
debug_enabled = true;
prefs.putBool("debug_enabled", true);
}
} else { } else {
ERROR("Unknown command: %s\n", cmd.c_str()); ERROR("Unknown command: %s\n", cmd.c_str());
return false; return false;

View File

@ -9,9 +9,24 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/272149490a.js" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/272149490a.js" crossorigin="anonymous"></script>
<style>
.overlay {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
position: absolute;
z-index: 1;
margin: auto 0px;
vertical-align: middle;
color: white;
font-size: 60px;
text-align: center;
}
</style>
</head> </head>
<body> <body>
<div id="overlay" class="overlay">Not connected...</div>
<div class="container bg-dark text-light"> <div class="container bg-dark text-light">
<div class="row"> <div class="row">
<div class="col-sm-1"> <div class="col-sm-1">
@ -104,7 +119,7 @@
<input type="text" class="form-control" id="input_url" /> <input type="text" class="form-control" id="input_url" />
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-primary" id="button_url_open">Go</button> <button class="btn btn-primary" id="button_url_open">Go</button>
<button class="btn btn-danger" id="button_url_add_mapping" style="display: none;"><i class="fa fa-arrows-alt-h"></i></button> <button class="btn btn-warning" id="button_url_add_mapping" style="display: none;"><i class="fa fa-arrows-alt-h"></i></button>
</div> </div>
</div> </div>
@ -273,10 +288,30 @@ process_ws_message = function(event) {
} }
var play_on_click = true; var play_on_click = true;
interval = null;
ws = null;
var start_reconnect_timer = function() {
console.log("start_reconnect_timer() running...");
$('#overlay').show();
interval = setInterval(connect_to_ws, 2500);
}
var connect_to_ws = function() {
if (!ws || ws.readyState >= ws.CLOSING) {
ws = new WebSocket("ws://" + location.host + "/ws");
ws.onopen = function() {
console.log("on_open() running...");
clearInterval(interval);
$('#overlay').hide();
};
ws.onmessage = process_ws_message;
ws.onclose = start_reconnect_timer;
}
}
$(function() { $(function() {
ws = new WebSocket("ws://" + location.host + "/ws"); start_reconnect_timer();
ws.onmessage = process_ws_message;
$('#volume_slider').change(function(e) { ws.send("volume=" + e.target.value); }); $('#volume_slider').change(function(e) { ws.send("volume=" + e.target.value); });
$('#button_play').click(function(e) { ws.send("play"); }); $('#button_play').click(function(e) { ws.send("play"); });

View File

@ -4,6 +4,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiMulti.h> #include <WiFiMulti.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <Preferences.h>
#include "main.h" #include "main.h"
#include "config.h" #include "config.h"
#include "controller.h" #include "controller.h"
@ -20,6 +21,10 @@ HTTPServer* http_server;
uint8_t SPIMaster::state = 0; uint8_t SPIMaster::state = 0;
bool debug_enabled = true;
bool trace_enabled = false;
Preferences prefs;
void wifi_connect() { void wifi_connect() {
INFO("Connecting to WiFi...\n"); INFO("Connecting to WiFi...\n");
WiFiMulti wifi; WiFiMulti wifi;
@ -69,6 +74,14 @@ void setup() {
INFO("ESMP3, version unknown (OTA_VERSION %d)\n", OTA_VERSION); INFO("ESMP3, version unknown (OTA_VERSION %d)\n", OTA_VERSION);
#endif #endif
INFO("Initializing...\n"); INFO("Initializing...\n");
prefs.begin("esmp3");
debug_enabled = prefs.getBool("debug_enabled", true);
trace_enabled = prefs.getBool("trace_enabled", false);
PIN_SPEAKER_L_SETUP();
PIN_SPEAKER_R_SETUP();
PIN_SPEAKER_L(LOW);
PIN_SPEAKER_R(LOW);
DEBUG("Setting up SPI...\n"); DEBUG("Setting up SPI...\n");
SPI.begin(); SPI.begin();

View File

@ -10,8 +10,6 @@ Player::Player(SPIMaster* s) {
_spi = s; _spi = s;
PIN_VS1053_XRESET_SETUP(); PIN_VS1053_XRESET_SETUP();
PIN_VS1053_XRESET(HIGH); PIN_VS1053_XRESET(HIGH);
PIN_SPEAKER_L_SETUP();
PIN_SPEAKER_R_SETUP();
_speaker_off(); _speaker_off();
_spi->disable(); _spi->disable();
PIN_VS1053_DREQ_SETUP(); PIN_VS1053_DREQ_SETUP();
@ -534,6 +532,7 @@ bool Player::play() {
if (_state != idle) return false; if (_state != idle) return false;
if (_current_playlist == NULL) return false; if (_current_playlist == NULL) return false;
if (_current_playlist->get_file_count()==0) return false; if (_current_playlist->get_file_count()==0) return false;
_speaker_on();
_current_playlist->start(); _current_playlist->start();
String file; String file;
if (!_current_playlist->get_current_file(&file)) { if (!_current_playlist->get_current_file(&file)) {

View File

@ -77,7 +77,6 @@ void Playlist::_examine_http_url(String url) {
String ct = http->getContentType(); String ct = http->getContentType();
DEBUG("Content-Type is %s.\n", ct.c_str()); DEBUG("Content-Type is %s.\n", ct.c_str());
if (ct.startsWith("audio/x-mpegurl")) { if (ct.startsWith("audio/x-mpegurl")) {
_parse_m3u(http); _parse_m3u(http);
} else if (ct.startsWith("audio/")) { } else if (ct.startsWith("audio/")) {
persistence = PERSIST_NONE; persistence = PERSIST_NONE;
@ -108,37 +107,44 @@ void xmlcb(uint8_t status, char* tagName, uint16_t tagLen, char* data, uint16_t
String tag(tagName); String tag(tagName);
if (status & STATUS_START_TAG) xml_last_tag = tag; if (status & STATUS_START_TAG) xml_last_tag = tag;
if (trace_enabled) {
if (status & STATUS_START_TAG) {
TRACE("Start of tag: %s\n", tagName);
} else if (status & STATUS_END_TAG) {
TRACE("End of tag: %s\n", tagName);
}
}
if (tag.equals("/rss/channel/title") && (status & STATUS_TAG_TEXT)) { if (tag.equals("/rss/channel/title") && (status & STATUS_TAG_TEXT)) {
xml_album_title = data; xml_album_title = data;
} else if (tag.endsWith("/item") && (status & STATUS_START_TAG)) { } else if (tag.endsWith("/title") && (status & STATUS_TAG_TEXT)) {
xml_title = "";
xml_url = "";
xml_guid = "";
} else if (tag.endsWith("/item/title") && (status & STATUS_TAG_TEXT)) {
xml_title = String(data); xml_title = String(data);
} else if (tag.endsWith("/item/guid") && (status & STATUS_TAG_TEXT)) { } else if (tag.endsWith("/guid") && (status & STATUS_TAG_TEXT)) {
xml_guid = data; xml_guid = data;
//} else if (xml_last_tag.endsWith("/item/enclosure") && (status & STATUS_ATTR_TEXT)) { //} else if (xml_last_tag.endsWith("/item/enclosure") && (status & STATUS_ATTR_TEXT)) {
// DEBUG("tag: %s, data: %s\n", tag.c_str(), data); // DEBUG("tag: %s, data: %s\n", tag.c_str(), data);
} else if (xml_last_tag.endsWith("/item/enclosure") && tag.equals("type") && (status & STATUS_ATTR_TEXT) && String(data).indexOf("audio/")>=0) { } else if (xml_last_tag.endsWith("/enclosure") && tag.equals("type") && (status & STATUS_ATTR_TEXT) && String(data).indexOf("audio/")>=0) {
DEBUG("enclosure is audio\n"); DEBUG("enclosure is audio\n");
xml_enclosure_is_audio = true; xml_enclosure_is_audio = true;
} else if (xml_last_tag.endsWith("/item/enclosure") && tag.equals("url") && (status & STATUS_ATTR_TEXT)) { } else if (xml_last_tag.endsWith("/enclosure") && tag.equals("url") && (status & STATUS_ATTR_TEXT)) {
DEBUG("found url\n"); DEBUG("found url\n");
xml_enclosure_url = String(data); xml_enclosure_url = String(data);
} else if (tag.endsWith("/item/enclosure") && (status & STATUS_END_TAG)) { } else if (tag.endsWith("/enclosure") && (status & STATUS_END_TAG)) {
DEBUG("end of enclosure. xml_enclosure_is_audio: %d, xml_enclosure_url: %s\n", xml_enclosure_is_audio, xml_enclosure_url.c_str()); DEBUG("end of enclosure. xml_enclosure_is_audio: %d, xml_enclosure_url: %s\n", xml_enclosure_is_audio, xml_enclosure_url.c_str());
if (xml_enclosure_is_audio && xml_enclosure_url.length()>0) { if (xml_enclosure_is_audio && xml_enclosure_url.length()>0) {
xml_url = xml_enclosure_url; xml_url = xml_enclosure_url;
} }
xml_enclosure_is_audio = false; xml_enclosure_is_audio = false;
xml_enclosure_url = ""; xml_enclosure_url = "";
} else if (tag.endsWith("/item") && (status & STATUS_END_TAG)) { } else if (tag.endsWith("/item") && (status & STATUS_END_TAG || status & STATUS_START_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; 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});
} }
xml_title = "";
xml_url = "";
xml_guid = "";
} }
} }
@ -178,7 +184,7 @@ void Playlist::_parse_m3u(HTTPClientWrapper* http) {
do { do {
i = http->read(); i = http->read();
char c = i; char c = i;
if (i>=-1 && c!='\r' && c!='\n') { if (i>=0 && c!='\r' && c!='\n') {
line += c; line += c;
} else { } else {
if (line.equals("#EXTM3U")) { if (line.equals("#EXTM3U")) {