Browse Source

Bringing dynamic button-layout finally in place

master
Torsten Stauder 4 years ago
parent
commit
385e80b568
  1. 1
      .vscode/settings.json
  2. 4
      PCBs/Wemos Lolin D32/README.md
  3. 4
      PCBs/Wemos Lolin32 SD_MMC PN5180/README.md
  4. 5
      PCBs/Wemos Lolin32/README.md
  5. 23
      README.md
  6. 4
      changelog.md
  7. 12
      html/management.html
  8. 29
      src/HTMLmanagement.h
  9. 292
      src/main.cpp
  10. 18
      src/settings-custom.h
  11. 18
      src/settings-espa1s.h
  12. 20
      src/settings-lolin32.h
  13. 18
      src/settings-lolin_d32.h
  14. 18
      src/settings-lolin_d32_pro.h
  15. 119
      src/settings.h
  16. 108
      src/values.h

1
.vscode/settings.json

@ -1,2 +1,3 @@
{
"cmake.configureOnOpen": false
}

4
PCBs/Wemos Lolin D32/README.md

@ -16,8 +16,10 @@
* Make sure to edit `settings.h` (HAL=3) and `settings-lolin_d32.h` according your needs.
* Disable `SD_MMC_1BIT_MODE` and `SINGLE_SPI_ENABLE` as these are not supported by this PCB.
* Enable `RFID_READER_TYPE_MFRC522_SPI` as other RFID-reader-types are not supported by this PCB.
* Enable `USEROTARY_ENABLE`.
* Enable buttons for previous, next, pause/play.
## PCB-Wiring (2 SPI-instances: RC522 + SD)
## PCB-Wiring (2 SPI-instances: RC522 + SD + 3 buttons + rotary encoder)
Uses two SPI-instances. The first one for the RFID-reader and the second for SD-card-reader. Please refer [Schematics](Pictures/Schematics.pdf) for reference.<br />
| ESP32 (GPIO) | Hardware | Pin | Comment |
| ------------- | --------------------- | ------ | ------------------------------------------------------------ |

4
PCBs/Wemos Lolin32 SD_MMC PN5180/README.md

@ -27,8 +27,10 @@ After providing PCBs based on RC522 / SD-SPI it was about time to integrate "the
* Disable `RFID_READER_TYPE_MFRC522_SPI` and `SINGLE_SPI_ENABLE`.
* Don't forget to add jumper for jp1! Connect the upper and the middle pin if you don't want to use LPCD. In this case PN5180 is switched off while deepsleep is active. Connect the middle and the lower pin in order to power PN5180 continously (which is mandatory for LPCD)
* Make sure [Pullup-resistor was removed](https://github.com/biologist79/ESPuino/blob/master/pictures/Pullup-removal.jpg) for GPIO2/MISO.
* Enable `USEROTARY_ENABLE`.
* Enable buttons for previous, next, pause/play.
## PCB-Wiring (2 SPI-instances: PN5180 + SD_MMC)
## PCB-Wiring (2 SPI-instances: PN5180 + SD_MMC + 3 buttons + rotary encoder)
Please refer [Schematics](Pictures/Schematics.pdf) for reference.<br />
| ESP32 (GPIO) | Hardware | Pin | Comment |
| ------------- | --------------------- | ------ | ------------------------------------------------------------ |

5
PCBs/Wemos Lolin32/README.md

@ -22,8 +22,9 @@ After I've been asked many times to provide a PCB, I finally did so :-) It makes
* Make sure to edit `settings.h` (HAL=1) and `settings-lolin32.h` according your needs (see table below).
* Disable `SD_MMC_1BIT_MODE` and `SINGLE_SPI_ENABLE` as these are not supported by this PCB.
* Enable `RFID_READER_TYPE_MFRC522_SPI` as other RFID-reader-types are not supported by this PCB.
## PCB-Wiring (2 SPI-instances: RC522 + SD)
* Enable `USEROTARY_ENABLE`.
* Enable buttons for previous, next, pause/play.
## PCB-Wiring (2 SPI-instances: RC522 + SD + 3 buttons + rotary encoder)
Uses two SPI-instances. The first one for the RFID-reader and the second for SD-card-reader. Please refer [Schematics](Pictures/Schematics.pdf) for reference.<br />
| ESP32 (GPIO) | Hardware | Pin | Comment |
| ------------- | --------------------- | ------ | ------------------------------------------------------------ |

23
README.md

@ -7,12 +7,14 @@
* DE: Ich habe ein primär deutschsprachiges Forum aufgesetzt, welches ich mit reichlich Doku versehen habe. Würde mich freuen, euch dort zu sehen: https://forum.espuino.de. Ihr könnt euch dort mit eurem Github-Login einloggen, jedoch auch "normal" anmelden.
## Changelog
Moved to [another location](changelog.md) as it became to prominent here. Only last three events are kept:
* 01.02.2020: Introducing PCB: Lolin32 with SD_MMC + PN5180
* 06.02.2020: German umlauts now supported. When uploading via FTP make sure to change charset to CP437.
* 09.02.2020: Added support for bluetooth-sink (a2dp). Thanks @grch87 & @elmar-ops for providing this feature! Please note: wifi not available is now coloured green as blue make totally sense for bluetooth :-)
* 25.02.2020: Added support for dynamic button-layout. Rotary-encoder is now optional and up to five buttons can be used.
* 25.02.2020: Actions can be freely assigned to buttons (multi-button(s), single-button(s) (short), single-button(s) (long))
* 25.02.2020: Added support for webcontrol: basic control (volume, play/pause, next, previous, first, last track) can now be controlled via webgui.
* 25.02.2020: Added support for .m4a and .wav-files.
Thanks @QDaniel for the idea + basic implementation (first three features named above)!
## Known bugs
* Some webstreams don't run. Guess it's a combination of saturated connection-pool and lack of heap-memory. Works probably better if ESP32-WROVER (e.g. Lolin D32 pro) is used, as this chip has PSRAM. Advice: Don't enable modules (e.g. MQTT) if you don't need them as this could save memory (and trouble).
* English translation for webgui is currently outdated. This will be fixed soon when i18n-support will be integrated.
* English translation for webgui is currently pretty outdated. This will be fixed soon when i18n-support will be integrated.
## ESPuino - what's that?
The basic idea of ESPuino is to provide a way, to use the Arduino-platform for a music-control-concept that supports locally stored music-files without DRM-restrictions. This basically means that RFID-tags are used to direct a music-player. Even for kids this concept is simple: place an RFID-object (card, character) on top of a box and the music starts to play. Place another RFID-object on it and anything else is played. Simple as that.
@ -50,12 +52,13 @@ The heart of my project is an ESP32 on a [Wemos Lolin32 development-board](https
* If everything ran fine, at the first run, ESPuino should open an access-point with the name "ESPuino". Join this WiFi with your computer (or mobile) and enter `192.168.4.1` to your webbrowser. Enter WiFi-credentials and the hostname. After saving the configuraton, restart ESPuino. Hint: I tried to connect this access-point via Android mobile. Basically that's no problem, but as my mobile detected there'd be no internet-connection, it keept LTE-connection open and prevented me from connecting to `192.168.4.1`. So if in doubts use a computer.
* After reboot ESPuino tries to join your WiFi (with the credentials previously entered). If that was successful, an IP is shown in the serial-console of Visual Studio Code. You can call ESPuino's GUI using a webbrowser via this IP; make sure to allow Javascript. If mDNS-feature is active in `src/settings.h`, you can use the hostname configured extended by .local instead the IP. So if you configured `espuino` as hostname, you can use `espuino.local` for webgui and FTP.
* Via FTP you can upload data (but don't expect it to be super fast). It's round about 185 kb/s if SD is in SPI-mode and 310 kB/s if SD is in MMC-mode.
* FTP needs to be activated after boot by pressing `PAUSE` + `NEXT`-buttons (in parallel) first! Neopixel flashes green (1x) if enabling was successful. It'll be disabled automatically after next reboot. Means: you have to enable it every time you need it (if reboot was in between). Sounds annoying and maybe it is, but's running this way in order to have more heap-memory available (for webstream) if FTP isn't running.
* FTP needs to be activated after boot! Don't forget to assign action `ENABLE_FTP_SERVER` in `settings.h` to be able to activate it. Neopixel flashes green (1x) if enabling was successful. It'll be disabled automatically after next reboot. Means: you have to enable it every time you need it (if reboot was in between). Sounds annoying and maybe it is, but's running this way in order to have more heap-memory available (for webstream) if FTP isn't running.
* Via webbrowser you can configure various settings and pair RFID-tags with actions. If MQTT/FTP-support was not compiled, their config-tabs won't appear.
## Prerequisites / tipps
* Open settings.h
* choose if optional modules (e.g. MQTT, FTP, Neopixel) should be compiled/enabled
* Make sure to edit/review button-layout. Default-design is three buttons and a rotary-encoder. All actions available are listed in `values.h` (values >= 100).
* For debugging-purposes serialDebug can be set to ERROR, NOTICE, INFO or DEBUG.
* If MQTT=yes, set the IP or hostname of the MQTT-server accordingly and check the MQTT-topics (states and commands)
* Advice: don't enable MQTT if there's no broker around because network-timeouts can really be a PITA.
@ -95,7 +98,7 @@ Depending on the develboard you're using and the needs you have, there are diffe
A lot of wiring is necessary to get ESPuino working. After my first experiments on a breadboard I soldered all the stuff onto a PCB in order to avoid wild-west-cabling. Especially for the interconnect between µC and uSD-card-reader make sure to use short wires (like 10cm or so)! As of my experience with a breadbord, male/male-connectors are better than female/female-connectors. Important: you can easily connect another I2S-DACs by just connecting them in parallel to the I2S-pins (DIN, BCLK, LRC). This is true for example if you plan to integrate a [line/headphone-pcb](https://www.adafruit.com/product/3678). In general, this runs fine. But unfortunately especially this board lacks of a headphone jack, that takes note if a plug is inserted or not. Best way is to use a [headphone jack](https://www.conrad.de/de/p/cliff-fcr1295-klinken-steckverbinder-3-5-mm-buchse-einbau-horizontal-polzahl-3-stereo-schwarz-1-st-705830.html) that has a pin that is pulled to GND, if there's no plug and vice versa. Using for example a MOSFET-circuit, this GND-signal can be inverted in a way, that MAX98357.SD is pulled down to GND if there's a plug. Doing that will mute MAX98537a and so turn off the speaker immediately if there's a plug and vice versa. Have a look at the PCB-folder in order to view the detailed solution. Here's an example for such a [headphone-pcb](https://github.com/biologist79/ESPuino/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TDA1308) that makes use of GND.<br />
Have a look at the PCB-folder. I provided PCBs for a number of develboards. Probably this makes things easier for you.
## Wiring (2 SPI-instances: RC522 + SD)
## Wiring (2 SPI-instances: RC522 + SD + 3 buttons + rotary-encoder)
Uses two SPI-instances. The first one for the RFID-reader and the second for SD-card-reader. This is also the [setup, I personally use](https://github.com/biologist79/ESPuino/tree/master/PCBs/Wemos%20Lolin32).<br />
| ESP32 (GPIO) | Hardware | Pin | Comment |
| ------------- | --------------------- | ------ | ------------------------------------------------------------ |
@ -150,7 +153,7 @@ In general I recommend using a [uSD-card-reader](https://www.ebay.de/itm/Micro-S
Make sure to enable `SD_MMC_1BIT_MODE` if you want to use this feature. Don't(!) enable `SINGLE_SPI_ENABLE`. SD-MMC-mode requires these fixed PINs listed above. You can find a good comparison of different SD-card-modes here: (https://www.instructables.com/Select-SD-Interface-for-ESP32/).
Advice: Double check that above PINs are not used elsewhere (e.g. GPIO2 is used as PREVIOUS_BUTTON as per default in settings.h).
## Wiring (1 SPI-instance: RC522 + SD) [EXPERIMENTAL, maybe not working!]
## Wiring (1 SPI-instance: RC522 + SD + 3 buttons + rotary-encoder) [EXPERIMENTAL, maybe not working!]
Basically the same as using 2 SPI-instances but...
In this case RFID-reader + SD-reader share SPI's SCK, MISO and MOSI. But make sure to use different CS-pins. Have to admit I had some problems to get this running. Seems to be connected properly, but nothing happens when an RFID-tag is applied. Maybe anybody else wants to point out :-)
@ -310,7 +313,8 @@ Please note: some Neopixels use a reversed addressing which leads to the 'proble
counter clockwise. If you want to change that behaviour, just enable `NEOPIXEL_REVERSE_ROTATION`.
### Buttons
Some buttons have different actions if pressed long or short. Minimum duration for long press in ms is defined by `intervalToLongPress`.
Important: this section describes my default-design: 3 buttons + rotary-encoder. Feel free to change button-number and button-actions according your needs in `settings.h` and your develboard-specific config-file (e.g. `settings-lolin32.h`). At maximum you can activate five buttons + rotary-encoder.
Minimum duration for long press in ms is defined by `intervalToLongPress`.
* previous (short): previous track / beginning of the first track if pressed while first track is playing
* previous (long): first track of playlist
* next (short): next track of playlist
@ -346,9 +350,10 @@ After having ESPuino running on your ESP32 in your local WiFi, the webinterface-
* (optional) MQTT-configuration (broker's IP)
* (optional) FTP-configuration (username and password)
* General-configuration (volume (speaker + headphone), neopixel-brightness (night-mode + initial), sleep after inactivity)
* Basic music-control: first, last, previous, next-track; volume +/-; play/pause
### FTP (optional)
* FTP needs to be activated after boot by pressing `PAUSE` + `NEXT`-buttons (in parallel) first! Neopixel flashes green (1x) if enabling was successful. It'll be disabled automatically after next reboot. Means: you have to enable it every time you need it (if reboot was in between). Sounds annoying and maybe it is, but's running this way in order to have more heap-memory available (for webstream) if FTP isn't running.
* FTP needs to be activated after boot! Don't forget to assign action `ENABLE_FTP_SERVER` in `settings.h` to be able to activate it! Neopixel flashes green (1x) if enabling was successful. It'll be disabled automatically after next reboot. Means: you have to enable it every time you need it (if reboot was in between). Sounds annoying and maybe it is, but's running this way in order to have more heap-memory available (for webstream) if FTP isn't running.
* In order to avoid exposing uSD-card or disassembling ESPuino 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.
* Make sure to set the max. number of parallel connections to ONE in your FTP-client and the charset to CP437. CP437 is important if you want to use german umlauts (öäüß).

4
changelog.md

@ -26,3 +26,7 @@
* 01.02.2020: Introducing PCB: Lolin32 with SD_MMC + PN5180
* 06.02.2020: German umlauts now supported. When uploading via FTP make sure to change charset to CP437.
* 09.02.2020: Added support for bluetooth-sink (a2dp). Thanks @grch87 & @elmar-ops for providing this feature!
* 25.02.2020: Added support for dynamic button-layout. Rotary-encoder is now optional and up to five buttons can be used.
* 25.02.2020: Actions can be freely assigned to buttons (multi-button, single-button (short), single-button (long))
* 25.02.2020: Added support for webcontrol: basic control (volume, play/pause, next, previous, first, last track) can now be controlled via webgui.
* 25.02.2020: Added support for .m4a and .wav-files.

12
html/management.html

@ -140,7 +140,7 @@
<br/>
<nav>
<div class="container nav nav-tabs" id="nav-tab" role="tablist">
<a class="nav-item nav-link" id="nav-control-tab" data-toggle="tab" href="#nav-control" role="tab" aria-controls="nav-control" aria-selected="false"><i class="fas fa-gamepad"></i><span class=".d-sm-none .d-md-block"> Control</span></a>
<a class="nav-item nav-link" id="nav-control-tab" data-toggle="tab" href="#nav-control" role="tab" aria-controls="nav-control" aria-selected="false"><i class="fas fa-gamepad"></i><span class=".d-sm-none .d-md-block"> Steuerung</span></a>
<a class="nav-item nav-link active" id="nav-rfid-tab" data-toggle="tab" href="#nav-rfid" role="tab" aria-controls="nav-rfid" aria-selected="true"><i class="fas fa-dot-circle"></i> RFID</a>
<a class="nav-item nav-link" id="nav-wifi-tab" data-toggle="tab" href="#nav-wifi" role="tab" aria-controls="nav-wifi" aria-selected="false"><i class="fas fa-wifi"></i><span class=".d-sm-none .d-md-block"> WLAN</span></a>
%SHOW_MQTT_TAB%
@ -177,7 +177,7 @@
</div>
</div>
<div class="tab-pane fade" id="nav-control" role="tabpanel" aria-labelledby="nav-control-tab">
<div class="container" id="navControl">
<div class="container" id="navControl">
<div class="form-group col-md-12">
<legend>Steuerung</legend>
<div class="buttons">
@ -196,13 +196,13 @@
<button type="button" class="btn btn-default btn-lg" onclick="sendControl(174)">
<span class="fas fa-fast-forward"></span>
</button>
</div>
</div>
</div>
<br>
<div class="form-group col-md-12">
<legend>Lautst&auml;rke</legend>
<i class="fas fa-volume-down fa-2x .icon-pos"></i> <input data-provide="slider" type="number" data-slider-min="1" data-slider-max="21" min="1" max="21" class="form-control" id="setVolume"
data-slider-value="%INIT_VOLUME%" value="%INIT_VOLUME%" onchange="sendVolume(this.value)"> <i class="fas fa-volume-up fa-2x .icon-pos"></i>
data-slider-value="%CURRENT_VOLUME%" value="%CURRENT_VOLUME%" onchange="sendVolume(this.value)"> <i class="fas fa-volume-up fa-2x .icon-pos"></i>
</div>
<br/>
</div>
@ -231,7 +231,7 @@
<div id="explorerUploadProgress" class="progress-bar" role="progressbar" ></div>
</div>
</div>
<br>
<br>
</div>
</fieldset>
</div>
@ -540,7 +540,7 @@
$('#explorerTree').on('select_node.jstree', function (e, data) {
$('input[name=fileOrUrl]').val(data.node.data.path);
if (ActiveSubTab !== 'rfid-music-tab') {
$('#SubTab.nav-tabs a[id="rfid-music-tab"]').tab('show');
}

29
src/HTMLmanagement.h

@ -120,6 +120,8 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
-webkit-appearance: none;\
-moz-appearance: none;\
appearance: none;\
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAAAAADhgtq/AAAACXBIWXMAAC4jAAAuIwF4pT92AAAAR0lEQVR4nGP5z4ADsOCSGOoyC+NRabjMQqjQQrgUTCYeIrQQyEI3DSyFJIHkApAUkgSy21B0oLo6fiGSBKp/kCUGU4hSRQYAYg0Rw+gGlUQAAAAASUVORK5CYII=') no-repeat;\
background-position: center right;\
}\
</style>\
</head>\
@ -138,7 +140,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<br/>\
<nav>\
<div class=\"container nav nav-tabs\" id=\"nav-tab\" role=\"tablist\">\
<a class=\"nav-item nav-link\" id=\"nav-control-tab\" data-toggle=\"tab\" href=\"#nav-control\" role=\"tab\" aria-controls=\"nav-control\" aria-selected=\"false\"><i class=\"fas fa-gamepad\"></i><span class=\".d-sm-none .d-md-block\"> Control</span></a>\
<a class=\"nav-item nav-link\" id=\"nav-control-tab\" data-toggle=\"tab\" href=\"#nav-control\" role=\"tab\" aria-controls=\"nav-control\" aria-selected=\"false\"><i class=\"fas fa-gamepad\"></i><span class=\".d-sm-none .d-md-block\"> Steuerung</span></a>\
<a class=\"nav-item nav-link active\" id=\"nav-rfid-tab\" data-toggle=\"tab\" href=\"#nav-rfid\" role=\"tab\" aria-controls=\"nav-rfid\" aria-selected=\"true\"><i class=\"fas fa-dot-circle\"></i> RFID</a>\
<a class=\"nav-item nav-link\" id=\"nav-wifi-tab\" data-toggle=\"tab\" href=\"#nav-wifi\" role=\"tab\" aria-controls=\"nav-wifi\" aria-selected=\"false\"><i class=\"fas fa-wifi\"></i><span class=\".d-sm-none .d-md-block\"> WLAN</span></a>\
%SHOW_MQTT_TAB%\
@ -175,7 +177,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
</div>\
</div>\
<div class=\"tab-pane fade\" id=\"nav-control\" role=\"tabpanel\" aria-labelledby=\"nav-control-tab\">\
<div class=\"container\" id=\"navControl\"> \
<div class=\"container\" id=\"navControl\">\
<div class=\"form-group col-md-12\">\
<legend>Steuerung</legend>\
<div class=\"buttons\">\
@ -194,13 +196,13 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<button type=\"button\" class=\"btn btn-default btn-lg\" onclick=\"sendControl(174)\">\
<span class=\"fas fa-fast-forward\"></span>\
</button>\
</div> \
</div>\
</div>\
<br>\
<div class=\"form-group col-md-12\">\
<legend>Lautst&auml;rke</legend>\
<i class=\"fas fa-volume-down fa-2x .icon-pos\"></i> <input data-provide=\"slider\" type=\"number\" data-slider-min=\"1\" data-slider-max=\"21\" min=\"1\" max=\"21\" class=\"form-control\" id=\"setVolume\"\
data-slider-value=\"%INIT_VOLUME%\" value=\"%INIT_VOLUME%\" onchange=\"sendVolume(this.value)\"> <i class=\"fas fa-volume-up fa-2x .icon-pos\"></i> \
data-slider-value=\"%CURRENT_VOLUME%\" value=\"%CURRENT_VOLUME%\" onchange=\"sendVolume(this.value)\"> <i class=\"fas fa-volume-up fa-2x .icon-pos\"></i>\
</div>\
<br/>\
</div>\
@ -223,15 +225,13 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<input name=\"uploaded_file\" id =\"uploaded_file\" onchange=\"$(this).parent().parent().find('.form-control').html($(this).val().split(/[\\|/]/).pop());\" style=\"display: none;\" type=\"file\" multiple>\
</span>\
</div>\
\
</form>\
<br>\
<div class=\"progress\">\
<div id=\"explorerUploadProgress\" class=\"progress-bar\" role=\"progressbar\" style=\"width: 0\"></div>\
\
</div>\
<div id=\"explorerUploadProgress\" class=\"progress-bar\" role=\"progressbar\" ></div>\
</div>\
<br>\
</div>\
<br>\
</div>\
</fieldset>\
</div>\
@ -259,6 +259,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<input type=\"text\" class=\"form-control\" id=\"fileOrUrl\" maxlength=\"255\" placeholder=\"z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3\" pattern=\"^[^\\^#]+$\" name=\"fileOrUrl\" required>\
<label for=\"playMode\">Abspielmodus</label>\
<select class=\"form-control\" id=\"playMode\" name=\"playMode\">\
<option class=\"placeholder\" disabled selected value=\"\">Modus auswählen</option>\
<option class=\"option-file\" value=\"1\">Einzelner Titel</option>\
<option class=\"option-file\" value=\"2\">Einzelner Titel (Endlosschleife)</option>\
<option class=\"option-file-and-folder\" value=\"3\">Hörbuch</option>\
@ -273,6 +274,7 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
<div class=\"tab-pane \" id=\"rfidmod\" role=\"tabpanel\">\
<label for=\"modId\"></label>\
<select class=\"form-control\" id=\"modId\" name=\"modId\">\
<option class=\"placeholder\" disabled selected value=\"\">Modifikation auswählen</option>\
<option value=\"100\">Tastensperre</option>\
<option value=\"101\">Schlafen nach 15 Minuten</option>\
<option value=\"102\">Schlafen nach 30 Minuten</option>\
@ -538,6 +540,10 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
$('#explorerTree').on('select_node.jstree', function (e, data) {\
\
$('input[name=fileOrUrl]').val(data.node.data.path);\
\
if (ActiveSubTab !== 'rfid-music-tab') {\
$('#SubTab.nav-tabs a[id=\"rfid-music-tab\"]').tab('show');\
}\
\
if (data.node.type == \"folder\") {\
$('.option-folder').show();\
@ -659,8 +665,9 @@ static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\
if (evt.lengthComputable) {\
var percentComplete = evt.loaded / evt.total;\
percentComplete = parseInt(percentComplete * 100);\
console.log(percentComplete);\
$(\"#explorerUploadProgress\").css(\"width\", percentComplete + \"%\").text(percentComplete);\
console.log(percentComplete);\
var percent = percentComplete + '%';\
$(\"#explorerUploadProgress\").css('width', percent).text(percent);\
}\
}, false);\
\

292
src/main.cpp

@ -15,7 +15,9 @@
#include "settings-custom.h" // Contains all user-relevant settings custom-board
#endif
#include <ESP32Encoder.h>
#ifdef USEROTARY_ENABLE
#include <ESP32Encoder.h>
#endif
#include "Arduino.h"
#include <WiFi.h>
#ifdef MDNS_ENABLE
@ -74,12 +76,7 @@
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <nvsDump.h>
#include "freertos/ringbuf.h"
#include "values.h"
#include "values.h"
// Serial-logging buffer
@ -285,7 +282,9 @@ IPAddress myIP;
#endif
// Rotary encoder-configuration
ESP32Encoder encoder;
#ifdef USEROTARY_ENABLE
ESP32Encoder encoder;
#endif
// HW-Timer
hw_timer_t *timer = NULL;
@ -301,7 +300,8 @@ typedef struct {
unsigned long lastReleasedTimestamp;
} t_button;
t_button buttons[6];
t_button buttons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button
uint8_t shutdownButton = 99; // Helper used for Neopixel: stores button-number of shutdown-button
Preferences prefsRfid;
Preferences prefsSettings;
@ -347,7 +347,7 @@ void buttonHandler();
void deepSleepManager(void);
void doButtonActions(void);
void doRfidCardModifications(const uint32_t mod);
void doCmdAction(const uint32_t mod);
void doCmdAction(const uint16_t mod);
bool dumpNvsToSd(char *_namespace, char *_destFile);
bool endsWith (const char *str, const char *suf);
bool fileValid(const char *_fileItem);
@ -394,8 +394,10 @@ void rfidPreferenceLookupHandler (void);
void sendWebsocketData(uint32_t client, uint8_t code);
void setupVolume(void);
void trackQueueDispatcher(const char *_sdFile, const uint32_t _lastPlayPos, const uint32_t _playMode, const uint16_t _trackLastPlayed);
void volumeHandler(const int32_t _minVolume, const int32_t _maxVolume);
void volumeToQueueSender(const int32_t _newVolume);
#ifdef USEROTARY_ENABLE
void rotaryVolumeHandler(const int32_t _minVolume, const int32_t _maxVolume);
#endif
void volumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary);
wl_status_t wifiManager(void);
bool writeWifiStatusToNVS(bool wifiStatus);
void bluetoothHandler(void);
@ -568,6 +570,16 @@ void doButtonActions(void) {
buttons[3].isPressed = false;
doCmdAction(BUTTON_MULTI_03);
}
else if (buttons[0].isPressed && buttons[4].isPressed) {
buttons[0].isPressed = false;
buttons[4].isPressed = false;
doCmdAction(BUTTON_MULTI_04);
}
else if (buttons[0].isPressed && buttons[5].isPressed) {
buttons[0].isPressed = false;
buttons[5].isPressed = false;
doCmdAction(BUTTON_MULTI_05);
}
else if (buttons[1].isPressed && buttons[2].isPressed) {
buttons[1].isPressed = false;
buttons[2].isPressed = false;
@ -578,11 +590,46 @@ void doButtonActions(void) {
buttons[3].isPressed = false;
doCmdAction(BUTTON_MULTI_13);
}
else if (buttons[1].isPressed && buttons[4].isPressed) {
buttons[1].isPressed = false;
buttons[4].isPressed = false;
doCmdAction(BUTTON_MULTI_14);
}
else if (buttons[1].isPressed && buttons[5].isPressed) {
buttons[1].isPressed = false;
buttons[5].isPressed = false;
doCmdAction(BUTTON_MULTI_15);
}
else if (buttons[2].isPressed && buttons[3].isPressed) {
buttons[2].isPressed = false;
buttons[3].isPressed = false;
doCmdAction(BUTTON_MULTI_23);
}
else if (buttons[2].isPressed && buttons[4].isPressed) {
buttons[2].isPressed = false;
buttons[4].isPressed = false;
doCmdAction(BUTTON_MULTI_24);
}
else if (buttons[2].isPressed && buttons[5].isPressed) {
buttons[2].isPressed = false;
buttons[5].isPressed = false;
doCmdAction(BUTTON_MULTI_25);
}
else if (buttons[3].isPressed && buttons[4].isPressed) {
buttons[3].isPressed = false;
buttons[4].isPressed = false;
doCmdAction(BUTTON_MULTI_34);
}
else if (buttons[3].isPressed && buttons[5].isPressed) {
buttons[3].isPressed = false;
buttons[5].isPressed = false;
doCmdAction(BUTTON_MULTI_35);
}
else if (buttons[4].isPressed && buttons[5].isPressed) {
buttons[4].isPressed = false;
buttons[5].isPressed = false;
doCmdAction(BUTTON_MULTI_45);
}
else {
for (uint8_t i=0; i < sizeof(buttons) / sizeof(buttons[0]); i++) {
if (buttons[i].isPressed) {
@ -812,9 +859,7 @@ void callback(const char *topic, const byte *payload, uint32_t length) {
// Loudness to change?
else if (strcmp_P(topic, topicLoudnessCmnd) == 0) {
unsigned long vol = strtoul(receivedString, NULL, 10);
volumeToQueueSender(vol);
encoder.clearCount();
encoder.setCount(vol * 2); // Update encoder-value to keep it in-sync with MQTT-updates
volumeToQueueSender(vol, true);
}
// Modify sleep-timer?
else if (strcmp_P(topic, topicSleepTimerCmnd) == 0) {
@ -1089,6 +1134,8 @@ bool fileValid(const char *_fileItem) {
(endsWith(_fileItem, ".mp3") || endsWith(_fileItem, ".MP3") ||
endsWith(_fileItem, ".aac") || endsWith(_fileItem, ".AAC") ||
endsWith(_fileItem, ".m3u") || endsWith(_fileItem, ".M3U") ||
endsWith(_fileItem, ".m4a") || endsWith(_fileItem, ".M4A") ||
endsWith(_fileItem, ".wav") || endsWith(_fileItem, ".WAV") ||
endsWith(_fileItem, ".asx") || endsWith(_fileItem, ".ASX"));
}
@ -1857,6 +1904,7 @@ void showLed(void *parameter) {
static bool notificationShown = false;
static bool volumeChangeShown = false;
static bool showEvenError = false;
static bool turnedOffLeds = false;
static uint8_t ledPosWebstream = 0;
static uint8_t ledSwitchInterval = 5; // time in secs (webstream-only)
static uint8_t webstreamColor = 0;
@ -1869,12 +1917,19 @@ void showLed(void *parameter) {
FastLED.setBrightness(ledBrightness);
for (;;) {
#ifdef NEOPIXEL_ENABLE
if (pauseNeopixel) { // Workaround to prevent exceptions while NVS-writes take place
vTaskDelay(portTICK_RATE_MS*10);
continue;
if (pauseNeopixel) { // Workaround to prevent exceptions while NVS-writes take place
vTaskDelay(portTICK_RATE_MS*10);
continue;
}
if (gotoSleep) { // If deepsleep is planned, turn off LEDs first in order to avoid LEDs still glowing when ESP32 is in deepsleep
if (!turnedOffLeds) {
FastLED.clear();
turnedOffLeds = true;
}
#endif
vTaskDelay(portTICK_RATE_MS*10);
continue;
}
if (!bootComplete) { // Rotates orange unless boot isn't complete
FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) {
@ -1908,18 +1963,26 @@ void showLed(void *parameter) {
lastLedBrightness = ledBrightness;
}
if (!buttons[3].currentState) {
FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[ledAddress(led)] = CRGB::Red;
if (buttons[3].currentState) {
// LEDs growing red as long button for sleepmode is pressed.
if (shutdownButton < (sizeof(buttons) / sizeof(buttons[0])) - 1) { // Only show animation, if CMD_SLEEPMODE was assigned to BUTTON_n_LONG + button is pressed
if (!buttons[shutdownButton].currentState) {
FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[ledAddress(led)] = CRGB::Red;
if (buttons[shutdownButton].currentState) {
FastLED.show();
delay(5);
deepSleepManager();
break;
}
FastLED.show();
delay(5);
deepSleepManager();
break;
vTaskDelay(intervalToLongPress / NUM_LEDS * portTICK_RATE_MS);
}
FastLED.show();
vTaskDelay(intervalToLongPress / NUM_LEDS * portTICK_RATE_MS);
}
} else {
shutdownButton = (sizeof(buttons) / sizeof(buttons[0])) - 1; // If CMD_SLEEPMODE was not assigned to an enabled button, dummy-button is used
if (!buttons[shutdownButton].currentState) {
buttons[shutdownButton].currentState = true;
}
}
@ -1994,7 +2057,7 @@ void showLed(void *parameter) {
}
for (uint8_t i=0; i<=100; i++) {
if (hlastVolume != currentVolume || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
break;
}
@ -2016,7 +2079,7 @@ void showLed(void *parameter) {
FastLED.show();
for (uint8_t i=0; i<=50; i++) {
if (hlastVolume != currentVolume || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
if (hlastVolume != currentVolume) {
volumeChangeShown = false;
}
@ -2032,7 +2095,7 @@ void showLed(void *parameter) {
for (uint8_t i=NUM_LEDS-1; i>0; i--) {
leds[ledAddress(i)] = CRGB::Black;
FastLED.show();
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
break;
} else {
vTaskDelay(portTICK_RATE_MS*30);
@ -2049,9 +2112,9 @@ void showLed(void *parameter) {
leds[ledAddress(i)] = CRGB::Blue;
FastLED.show();
#ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[shutdownButton].currentState || gotoSleep) {
#else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
#endif
break;
} else {
@ -2061,9 +2124,9 @@ void showLed(void *parameter) {
for (uint8_t i=0; i<=100; i++) {
#ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[shutdownButton].currentState || gotoSleep) {
#else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
#endif
break;
} else {
@ -2075,9 +2138,9 @@ void showLed(void *parameter) {
leds[ledAddress(i)-1] = CRGB::Black;
FastLED.show();
#ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[shutdownButton].currentState || gotoSleep) {
#else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[shutdownButton].currentState || gotoSleep) {
#endif
break;
} else {
@ -2119,9 +2182,9 @@ void showLed(void *parameter) {
FastLED.show();
for (uint8_t i=0; i<=50; i++) {
#ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || playProperties.playMode != NO_PLAYLIST || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || playProperties.playMode != NO_PLAYLIST || !buttons[shutdownButton].currentState || gotoSleep) {
#else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || playProperties.playMode != NO_PLAYLIST || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || playProperties.playMode != NO_PLAYLIST || !buttons[shutdownButton].currentState || gotoSleep) {
#endif
break;
} else {
@ -2158,9 +2221,9 @@ void showLed(void *parameter) {
default: // If playlist is active (doesn't matter which type)
if (!playProperties.playlistFinished) {
#ifdef MEASURE_BATTERY_VOLTAGE
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || showVoltageWarning || showLedVoltage || !buttons[shutdownButton].currentState || gotoSleep) {
#else
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || !buttons[3].currentState) {
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || !buttons[shutdownButton].currentState || gotoSleep) {
#endif
lastPlayState = playProperties.pausePlay;
lastLockState = lockControls;
@ -2322,14 +2385,24 @@ void deepSleepManager(void) {
// Adds new volume-entry to volume-queue
void volumeToQueueSender(const int32_t _newVolume) {
// If volume is changed via webgui or MQTT, it's necessary to re-adjust current value of rotary-encoder.
void volumeToQueueSender(const int32_t _newVolume, bool reAdjustRotary) {
uint32_t _volume;
if (_newVolume <= minVolume) {
_volume = minVolume;
if (_newVolume < minVolume) {
loggerNl(serialDebug, (char *) FPSTR(minLoudnessReached), LOGLEVEL_INFO);
return;
} else if (_newVolume > maxVolume) {
_volume = maxVolume;
loggerNl(serialDebug, (char *) FPSTR(maxLoudnessReached), LOGLEVEL_INFO);
return;
} else {
_volume = _newVolume;
currentVolume = _volume;
#ifdef USEROTARY_ENABLE
if (reAdjustRotary) {
encoder.clearCount();
encoder.setCount(currentVolume * 2);
}
#endif
}
xQueueSend(volumeQueue, &_volume, 0);
}
@ -2342,36 +2415,38 @@ void trackControlToQueueSender(const uint8_t trackCommand) {
// Handles volume directed by rotary encoder
void volumeHandler(const int32_t _minVolume, const int32_t _maxVolume) {
if (lockControls) {
encoder.clearCount();
encoder.setCount(currentVolume*2);
return;
}
currentEncoderValue = encoder.getCount();
// Only if initial run or value has changed. And only after "full step" of rotary encoder
if (((lastEncoderValue != currentEncoderValue) || lastVolume == -1) && (currentEncoderValue % 2 == 0)) {
lastTimeActiveTimestamp = millis(); // Set inactive back if rotary encoder was used
if (_maxVolume * 2 < currentEncoderValue) {
encoder.clearCount();
encoder.setCount(_maxVolume * 2);
loggerNl(serialDebug, (char *) FPSTR(maxLoudnessReached), LOGLEVEL_INFO);
currentEncoderValue = encoder.getCount();
} else if (currentEncoderValue < _minVolume) {
#ifdef USEROTARY_ENABLE
void rotaryVolumeHandler(const int32_t _minVolume, const int32_t _maxVolume) {
if (lockControls) {
encoder.clearCount();
encoder.setCount(_minVolume);
loggerNl(serialDebug, (char *) FPSTR(minLoudnessReached), LOGLEVEL_INFO);
currentEncoderValue = encoder.getCount();
encoder.setCount(currentVolume*2);
return;
}
lastEncoderValue = currentEncoderValue;
currentVolume = lastEncoderValue / 2;
if (currentVolume != lastVolume) {
lastVolume = currentVolume;
volumeToQueueSender(currentVolume);
currentEncoderValue = encoder.getCount();
// Only if initial run or value has changed. And only after "full step" of rotary encoder
if (((lastEncoderValue != currentEncoderValue) || lastVolume == -1) && (currentEncoderValue % 2 == 0)) {
lastTimeActiveTimestamp = millis(); // Set inactive back if rotary encoder was used
if (_maxVolume * 2 < currentEncoderValue) {
encoder.clearCount();
encoder.setCount(_maxVolume * 2);
loggerNl(serialDebug, (char *) FPSTR(maxLoudnessReached), LOGLEVEL_INFO);
currentEncoderValue = encoder.getCount();
} else if (currentEncoderValue < _minVolume) {
encoder.clearCount();
encoder.setCount(_minVolume);
loggerNl(serialDebug, (char *) FPSTR(minLoudnessReached), LOGLEVEL_INFO);
currentEncoderValue = encoder.getCount();
}
lastEncoderValue = currentEncoderValue;
currentVolume = lastEncoderValue / 2;
if (currentVolume != lastVolume) {
lastVolume = currentVolume;
volumeToQueueSender(currentVolume, false);
}
}
}
}
#endif
// Receives de-serialized RFID-data (from NVS) and dispatches playlists for the given
@ -2565,7 +2640,7 @@ void doRfidCardModifications(const uint32_t mod) {
doCmdAction(mod);
}
void doCmdAction(const uint32_t mod) {
void doCmdAction(const uint16_t mod) {
switch (mod) {
case LOCK_BUTTONS_MOD: { // Locks/unlocks all buttons
lockControls = !lockControls;
@ -2583,6 +2658,7 @@ void doCmdAction(const uint32_t mod) {
publishMqtt((char *) FPSTR(topicLockControlsState), "OFF", false);
#endif
}
break;
}
case SLEEP_TIMER_MOD_15: { // Enables/disables sleep after 15 minutes
@ -2980,15 +3056,15 @@ void doCmdAction(const uint32_t mod) {
break;
}
case CMD_VOLUMEINIT: {
volumeToQueueSender(initVolume);
volumeToQueueSender(initVolume, true);
break;
}
case CMD_VOLUMEUP: {
volumeToQueueSender(currentVolume + 2);
volumeToQueueSender(currentVolume+1, true);
break;
}
case CMD_VOLUMEDOWN: {
volumeToQueueSender(currentVolume - 2);
volumeToQueueSender(currentVolume-1, true);
break;
}
case CMD_MEASUREBATTERY: {
@ -3321,6 +3397,8 @@ String templateProcessor(const String& templ) {
return String(prefsSettings.getUInt("mInactiviyT", 0));
} else if (templ == "INIT_VOLUME") {
return String(prefsSettings.getUInt("initVolume", 0));
} else if (templ == "CURRENT_VOLUME") {
return String(currentVolume);
} else if (templ == "MAX_VOLUME_SPEAKER") {
return String(prefsSettings.getUInt("maxVolumeSp", 0));
} else if (templ == "MAX_VOLUME_HEADPHONE") {
@ -3510,14 +3588,12 @@ bool processJsonRequest(char *_serialJson) {
} else if (doc.containsKey("ping")) {
sendWebsocketData(0, 20);
return false;
}else if (doc.containsKey("controls")) {
if(object["controls"].containsKey("set_volume"))
{
} else if (doc.containsKey("controls")) {
if (object["controls"].containsKey("set_volume")) {
uint8_t new_vol = doc["controls"]["set_volume"].as<uint8_t>();
volumeToQueueSender(new_vol);
volumeToQueueSender(new_vol, true);
}
if(object["controls"].containsKey("action"))
{
if (object["controls"].containsKey("action")) {
uint8_t cmd = doc["controls"]["action"].as<uint8_t>();
doCmdAction(cmd);
}
@ -3622,7 +3698,7 @@ void setupVolume(void) {
} else {
maxVolume = maxVolumeHeadphone;
if (currentVolume > maxVolume) {
volumeToQueueSender(maxVolume); // Lower volume for headphone if headphone's maxvolume is exceeded by volume set in speaker-mode
volumeToQueueSender(maxVolume, true); // Lower volume for headphone if headphone's maxvolume is exceeded by volume set in speaker-mode
}
}
headphoneLastDetectionState = currentHeadPhoneDetectionState;
@ -4205,7 +4281,43 @@ void printWakeUpReason() {
void setup() {
Serial.begin(115200);
esp_sleep_enable_ext0_wakeup((gpio_num_t) DREHENCODER_BUTTON, 0);
#if (WAKEUP_BUTTON <= 39)
esp_sleep_enable_ext0_wakeup((gpio_num_t) WAKEUP_BUTTON, 0);
#endif
#ifdef NEOPIXEL_ENABLE // Try to find button that is used for shutdown via longpress-action (only necessary for Neopixel)
#ifdef BUTTON_0_ENABLE
#if (BUTTON_0_LONG == CMD_SLEEPMODE)
shutdownButton = 0;
#endif
#endif
#ifdef BUTTON_1_ENABLE
#if (BUTTON_1_LONG == CMD_SLEEPMODE)
shutdownButton = 1;
#endif
#endif
#ifdef BUTTON_2_ENABLE
#if (BUTTON_2_LONG == CMD_SLEEPMODE)
shutdownButton = 2;
#endif
#endif
#ifdef BUTTON_3_ENABLE
#if (BUTTON_3_LONG == CMD_SLEEPMODE)
shutdownButton = 3;
#endif
#endif
#ifdef BUTTON_4_ENABLE
#if (BUTTON_4_LONG == CMD_SLEEPMODE)
shutdownButton = 4;
#endif
#endif
#ifdef BUTTON_5_ENABLE
#if (BUTTON_5_LONG == CMD_SLEEPMODE)
shutdownButton = 5;
#endif
#endif
#endif
#ifdef PN5180_ENABLE_LPCD
// disable pin hold from deep sleep (LPCD)
gpio_deep_sleep_hold_dis();
@ -4630,9 +4742,11 @@ void setup() {
unsigned long currentTimestamp = millis();
// Init rotary encoder
encoder.attachHalfQuad(DREHENCODER_CLK, DREHENCODER_DT);
encoder.clearCount();
encoder.setCount(initVolume*2); // Ganzes Raster ist immer +2, daher initiale Lautstärke mit 2 multiplizieren
#ifdef USEROTARY_ENABLE
encoder.attachHalfQuad(DREHENCODER_CLK, DREHENCODER_DT);
encoder.clearCount();
encoder.setCount(initVolume*2); // Ganzes Raster ist immer +2, daher initiale Lautstärke mit 2 multiplizieren
#endif
// Only enable MQTT if requested
#ifdef MQTT_ENABLE
@ -4703,7 +4817,9 @@ void loop() {
#ifdef FTP_ENABLE
ftpManager();
#endif
volumeHandler(minVolume, maxVolume);
#ifdef USEROTARY_ENABLE
rotaryVolumeHandler(minVolume, maxVolume);
#endif
if (wifiManager() == WL_CONNECTED) {
#ifdef MQTT_ENABLE
if (enableMqtt) {

18
src/settings-custom.h

@ -44,16 +44,22 @@
#define I2S_LRC 26 // LRC (I2S)
// Rotary encoder
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 35 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button 3: is used to switch ESPuino on and off
#ifdef USEROTARY_ENABLE
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 35 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button 3: is used to switch ESPuino on and off
#endif
// Control-buttons
// Control-buttons (set to 99 to disable)
#define NEXT_BUTTON 4 // Button 0: GPIO to detect next
#define PREVIOUS_BUTTON 2 // Button 1: GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2; make sure to change in SD-MMC-mode)
#define PAUSEPLAY_BUTTON 0 // Button 2: GPIO to detect pause/play
#define BUTTON_4 99 // Button 4
#define BUTTON_5 99 // Button 5
#define BUTTON_4 99 // Button 4: unnamed optional button
#define BUTTON_5 99 // Button 5: unnamed optional button
// Wake-up button
// Please note: only RTC-GPIOs (0, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 39, 99) can be used! Set to 99 to disable.
#define WAKEUP_BUTTON DREHENCODER_BUTTON // Defines the button that is used to wake up ESPuino from deepsleep.
// (optional) Power-control
#define POWER 17 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep

18
src/settings-espa1s.h

@ -38,16 +38,22 @@
#define GPIO_SEL_PA_EN GPIO_SEL_21
// Rotary encoder
#define DREHENCODER_CLK 5 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 18 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 4 // Button 3: is used to switch ESPuino on and off
#ifdef USEROTARY_ENABLE
#define DREHENCODER_CLK 5 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 18 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 4 // Button 3: is used to switch ESPuino on and off
#endif
// Control-buttons
// Control-buttons (set to 99 to disable)
#define NEXT_BUTTON 199 // Button 0: GPIO to detect next
#define PREVIOUS_BUTTON 198 // Button 1: GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2; make sure to change in SD-MMC-mode)
#define PAUSEPLAY_BUTTON 36 // Button 2: GPIO to detect pause/play
#define BUTTON_4 99 // Button 4
#define BUTTON_5 99 // Button 5
#define BUTTON_4 99 // Button 4: unnamed optional button
#define BUTTON_5 99 // Button 5: unnamed optional button
// Wake-up button
// Please note: only RTC-GPIOs (0, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 39, 99) can be used! Set to 99 to disable.
#define WAKEUP_BUTTON DREHENCODER_BUTTON // Defines the button that is used to wake up ESPuino from deepsleep.
// Power-control
#define POWER 19 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep

20
src/settings-lolin32.h

@ -34,7 +34,7 @@
// RFID (via SPI)
#define RST_PIN 99 // Not necessary but has to be set anyway; so let's use a dummy-number
#define RFID_CS 5 // GPIO for chip select (RFID)
#define RFID_CS 21 // GPIO for chip select (RFID)
#define RFID_MOSI 23 // GPIO for master out slave in (RFID)
#define RFID_MISO 19 // GPIO for master in slave out (RFID)
#define RFID_SCK 18 // GPIO for clock-signal (RFID)
@ -50,16 +50,22 @@
#define I2S_LRC 26 // LRC (I2S)
// Rotary encoder
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 35 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button 3: is used to switch ESPuino on and off
#ifdef USEROTARY_ENABLE
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 35 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button 3: is used to switch ESPuino on and off
#endif
// Control-buttons
// Control-buttons (set to 99 to disable)
#define NEXT_BUTTON 4 // Button 0: GPIO to detect next
#define PREVIOUS_BUTTON 2 // Button 1: GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2; make sure to change in SD-MMC-mode)
#define PAUSEPLAY_BUTTON 5 // Button 2: GPIO to detect pause/play
#define BUTTON_4 99 // Button 4
#define BUTTON_5 99 // Button 5
#define BUTTON_4 99 // Button 4: unnamed optional button
#define BUTTON_5 99 // Button 5: unnamed optional button
// Wake-up button
// Please note: only RTC-GPIOs (0, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 39, 99) can be used! Set to 99 to disable.
#define WAKEUP_BUTTON DREHENCODER_BUTTON // Defines the button that is used to wake up ESPuino from deepsleep.
// (optional) Power-control
#define POWER 17 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep

18
src/settings-lolin_d32.h

@ -51,16 +51,22 @@
#define I2S_LRC 26 // LRC (I2S)
// Rotary encoder
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 33 // Info: Lolin D32 / Lolin D32 pro 35 are using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button is used to switch ESPuino on and off
#ifdef USEROTARY_ENABLE
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 33 // Info: Lolin D32 is using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 32 // Button is used to switch ESPuino on and off
#endif
// Control-buttons
// Control-buttons (set to 99 to disable)
#define NEXT_BUTTON 4 // Button 0: GPIO to detect next
#define PREVIOUS_BUTTON 2 // Button 1: GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2; make sure to change in SD-MMC-mode)
#define PAUSEPLAY_BUTTON 5 // Button 2: GPIO to detect pause/play
#define BUTTON_4 99 // Button 4
#define BUTTON_5 99 // Button 5
#define BUTTON_4 99 // Button 4: unnamed optional button
#define BUTTON_5 99 // Button 5: unnamed optional button
// Wake-up button
// Please note: only RTC-GPIOs (0, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 39, 99) can be used! Set to 99 to disable.
#define WAKEUP_BUTTON DREHENCODER_BUTTON // Defines the button that is used to wake up ESPuino from deepsleep.
// (optional) Power-control
#define POWER 17 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep

18
src/settings-lolin_d32_pro.h

@ -46,16 +46,22 @@
#define I2S_LRC 26 // LRC (I2S)
// Rotary encoder
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 39 // 39 = 'VN'
#define DREHENCODER_BUTTON 36 // Button 3: is used to switch ESPuino on and off; 36 = 'VP'
#ifdef USEROTARY_ENABLE
#define DREHENCODER_CLK 34 // If you want to reverse encoder's direction, just switch GPIOs of CLK with DT (in software or hardware)
#define DREHENCODER_DT 39 // 39 = 'VN'; Info: Lolin D32 pro is using 35 for battery-voltage-monitoring!
#define DREHENCODER_BUTTON 36 // Button 3: is used to switch ESPuino on and off; 36 = 'VP'
#endif
// Control-buttons
// Control-buttons (set to 99 to disable)
#define NEXT_BUTTON 0 // Button 0: GPIO to detect next
#define PREVIOUS_BUTTON 2 // Button 1: GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2; make sure to change in SD-MMC-mode)
#define PAUSEPLAY_BUTTON 32 // Button 2: GPIO to detect pause/play
#define BUTTON_4 99 // Button 4
#define BUTTON_5 99 // Button 5
#define BUTTON_4 99 // Button 4: unnamed optional button
#define BUTTON_5 99 // Button 5: unnamed optional button
// Wake-up button
// Please note: only RTC-GPIOs (0, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, 39, 99) can be used! Set to 99 to disable.
#define WAKEUP_BUTTON DREHENCODER_BUTTON // Defines the button that is used to wake up ESPuino from deepsleep.
// (optional) Power-control
#define POWER 5 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep

119
src/settings.h

@ -30,7 +30,7 @@
#define MEASURE_BATTERY_VOLTAGE // Enables battery-measurement via GPIO (ADC) and voltage-divider
//#define PLAY_LAST_RFID_AFTER_REBOOT // When restarting ESPuino, the last RFID that was active before, is recalled and played
//#define USE_LAST_VOLUME_AFTER_REBOOT // Remembers the volume used at last shutdown after reboot
#define USEROTARY_ENABLE // If rotary-encoder is used
#define USEROTARY_ENABLE // If rotary-encoder is used (don't forget to review WAKEUP_BUTTON if you disable this feature!)
#define BLUETOOTH_ENABLE // If enabled and bluetooth-mode is active, you can stream to your ESPuino via bluetooth (a2dp-sink).
@ -54,6 +54,63 @@
#endif
//################## BUTTON-Layout ##################################
/* Please note the following numbers as you need to know them in order to define actions for buttons.
Even if you don't use all of them, their numbers won't change
0: NEXT_BUTTON
1: PREVIOUS_BUTTON
2: PAUSEPLAY_BUTTON
3: DREHENCODER_BUTTON
4: BUTTON_4
5: BUTTON_5
Don't forget to enable/configure those buttons you want to use in your develboard-specific config (e.g. settings-custom.h)
Single-buttons [can be long or short] (examples):
BUTTON_0_SHORT => Button 0 (NEXT_BUTTON) pressed shortly
BUTTON_3_SHORT => Button 3 (DREHENCODER_BUTTON) pressed shortly
BUTTON_4_LONG => Button 4 (BUTTON_4) pressed long
Multi-buttons [short only] (examples):
BUTTON_MULTI_01 => Buttons 0+1 (NEXT_BUTTON + PREVIOUS_BUTTON) pressed in parallel
BUTTON_MULTI_23 => Buttons 0+2 (NEXT_BUTTON + PAUSEPLAY_BUTTON) pressed in parallel
Actions:
To all of those buttons, an action can be assigned freely.
Please have a look at values.h to look up actions available (>=100 can be used)
If you don't want to assign an action or you don't use a given button: CMD_NOTHING has to be set
*/
// *****BUTTON***** *****ACTION*****
#define BUTTON_0_SHORT CMD_NEXTTRACK
#define BUTTON_1_SHORT CMD_PREVTRACK
#define BUTTON_2_SHORT CMD_PLAYPAUSE
#define BUTTON_3_SHORT CMD_MEASUREBATTERY
#define BUTTON_4_SHORT CMD_NOTHING
#define BUTTON_5_SHORT CMD_NOTHING
#define BUTTON_0_LONG CMD_LASTTRACK
#define BUTTON_1_LONG CMD_FIRSTTRACK
#define BUTTON_2_LONG CMD_PLAYPAUSE
#define BUTTON_3_LONG CMD_SLEEPMODE
#define BUTTON_4_LONG CMD_NOTHING
#define BUTTON_5_LONG CMD_NOTHING
#define BUTTON_MULTI_01 TOGGLE_WIFI_STATUS
#define BUTTON_MULTI_02 ENABLE_FTP_SERVER
#define BUTTON_MULTI_03 CMD_NOTHING
#define BUTTON_MULTI_04 CMD_NOTHING
#define BUTTON_MULTI_05 CMD_NOTHING
#define BUTTON_MULTI_12 CMD_NOTHING
#define BUTTON_MULTI_13 CMD_NOTHING
#define BUTTON_MULTI_14 CMD_NOTHING
#define BUTTON_MULTI_15 CMD_NOTHING
#define BUTTON_MULTI_23 CMD_NOTHING
#define BUTTON_MULTI_24 CMD_NOTHING
#define BUTTON_MULTI_25 CMD_NOTHING
#define BUTTON_MULTI_34 CMD_NOTHING
#define BUTTON_MULTI_35 CMD_NOTHING
#define BUTTON_MULTI_45 CMD_NOTHING
//#################### Various settings ##############################
// Loglevels available (don't change!)
#define LOGLEVEL_ERROR 1 // only errors
@ -143,63 +200,3 @@ float voltageIndicatorHigh = 4.2; // Upper range for Neopixel-
static const char topicBatteryVoltage[] PROGMEM = "State/ESPuino/Voltage";
#endif
#endif
#if defined RFID_READER_TYPE_MFRC522_SPI || defined RFID_READER_TYPE_MFRC522_I2C
#define RFID_CARDMAN
#endif
#define CHUNK_SIZE 1024
// Button-layout
/* Please note the following numbers as you need to know them in order to define actions for buttons.
Even if you don't use all of them, their numbers won't change
0: NEXT_BUTTON
1: PREVIOUS_BUTTON
2: PAUSEPLAY_BUTTON
3: DREHENCODER_BUTTON
4: BUTTON_4
5: BUTTON_5
Don't forget to enable those buttons you want to use in your develboard-specific config (e.g. settings-custom.h)
Multi-buttons (examples):
BUTTON_MULTI_01 => Buttons 0+1 (NEXT+PREVIOUS) pressed in parallel
BUTTON_MULTI_23 => Buttons 0+2 (NEXT+PAUSEPLAY_BUTTON) pressed in parallel
Single-buttons (examples):
BUTTON_0_SHORT => Button 0 (NEXT) pressed shortly
BUTTON_3_SHORT => Button 3 (DREHENCODER) pressed shortly
Actions:
To all of those buttons, an action can be assigned freely.
Please have a look at values.h to look up actions available (>100 can be used)
*/
// *****BUTTON***** *****ACTION*****
#define BUTTON_MULTI_01 TOGGLE_WIFI_STATUS
#define BUTTON_MULTI_02 ENABLE_FTP_SERVER
#define BUTTON_MULTI_03 CMD_NOTHING
#define BUTTON_MULTI_12 CMD_NOTHING
#define BUTTON_MULTI_13 CMD_NOTHING
#define BUTTON_MULTI_23 CMD_NOTHING
#define BUTTON_0_SHORT CMD_NEXTTRACK
#define BUTTON_1_SHORT CMD_PREVTRACK
#define BUTTON_2_SHORT CMD_PLAYPAUSE
#define BUTTON_3_SHORT CMD_MEASUREBATTERY
#define BUTTON_3_LONG CMD_SLEEPMODE
#define BUTTON_4_SHORT CMD_VOLUMEDOWN
#define BUTTON_4_LONG CMD_VOLUMEDOWN
#define BUTTON_5_SHORT CMD_VOLUMEUP
#define BUTTON_5_LONG CMD_VOLUMEUP
#ifdef USEROTARY_ENABLE
#define BUTTON_0_LONG CMD_LASTTRACK
#define BUTTON_1_LONG CMD_FIRSTTRACK
#define BUTTON_2_LONG CMD_PLAYPAUSE
#else
#define BUTTON_0_LONG CMD_VOLUMEDOWN
#define BUTTON_1_LONG CMD_VOLUMEUP
#define BUTTON_2_LONG CMD_SLEEPMODE
#endif

108
src/values.h

@ -1,65 +1,65 @@
#ifndef __ESPUINO_VALUES_H__
#define __ESPUINO_VALUES_H__
// Operation Mode
#define OPMODE_NORMAL 0 // Normal mode
#define OPMODE_BLUETOOTH 1 // Bluetooth mode. WiFi is deactivated. Music from SD and webstreams can't be played.
// Operation Mode
#define OPMODE_NORMAL 0 // Normal mode
#define OPMODE_BLUETOOTH 1 // Bluetooth mode. WiFi is deactivated. Music from SD and webstreams can't be played.
// Track-Control
#define STOP 1 // Stop play
#define PLAY 2 // Start play (currently not used)
#define PAUSEPLAY 3 // Pause/play
#define NEXTTRACK 4 // Next track of playlist
#define PREVIOUSTRACK 5 // Previous track of playlist
#define FIRSTTRACK 6 // First track of playlist
#define LASTTRACK 7 // Last track of playlist
// Track-Control
#define STOP 1 // Stop play
#define PLAY 2 // Start play (currently not used)
#define PAUSEPLAY 3 // Pause/play
#define NEXTTRACK 4 // Next track of playlist
#define PREVIOUSTRACK 5 // Previous track of playlist
#define FIRSTTRACK 6 // First track of playlist
#define LASTTRACK 7 // Last track of playlist
// Playmodes
#define NO_PLAYLIST 0 // If no playlist is active
#define SINGLE_TRACK 1 // Play a single track
#define SINGLE_TRACK_LOOP 2 // Play a single track in infinite-loop
#define AUDIOBOOK 3 // Single track, can save last play-position
#define AUDIOBOOK_LOOP 4 // Single track as infinite-loop, can save last play-position
#define ALL_TRACKS_OF_DIR_SORTED 5 // Play all files of a directory (alph. sorted)
#define ALL_TRACKS_OF_DIR_RANDOM 6 // Play all files of a directory (randomized)
#define ALL_TRACKS_OF_DIR_SORTED_LOOP 7 // Play all files of a directory (alph. sorted) in infinite-loop
#define ALL_TRACKS_OF_DIR_RANDOM_LOOP 9 // Play all files of a directory (randomized) in infinite-loop
#define WEBSTREAM 8 // Play webradio-stream
#define BUSY 10 // Used if playlist is created
// Playmodes
#define NO_PLAYLIST 0 // If no playlist is active
#define SINGLE_TRACK 1 // Play a single track
#define SINGLE_TRACK_LOOP 2 // Play a single track in infinite-loop
#define AUDIOBOOK 3 // Single track, can save last play-position
#define AUDIOBOOK_LOOP 4 // Single track as infinite-loop, can save last play-position
#define ALL_TRACKS_OF_DIR_SORTED 5 // Play all files of a directory (alph. sorted)
#define ALL_TRACKS_OF_DIR_RANDOM 6 // Play all files of a directory (randomized)
#define ALL_TRACKS_OF_DIR_SORTED_LOOP 7 // Play all files of a directory (alph. sorted) in infinite-loop
#define ALL_TRACKS_OF_DIR_RANDOM_LOOP 9 // Play all files of a directory (randomized) in infinite-loop
#define WEBSTREAM 8 // Play webradio-stream
#define BUSY 10 // Used if playlist is created
// RFID-modifcation-types
#define CMD_NOTHING 0 // Do Nothing
#define LOCK_BUTTONS_MOD 100 // Locks all buttons and rotary encoder
#define SLEEP_TIMER_MOD_15 101 // Puts uC into deepsleep after 15 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_30 102 // Puts uC into deepsleep after 30 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_60 103 // Puts uC into deepsleep after 60 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_120 104 // Puts uC into deepsleep after 120 minutes + LED-DIMM
#define SLEEP_AFTER_END_OF_TRACK 105 // Puts uC into deepsleep after track is finished + LED-DIMM
#define SLEEP_AFTER_END_OF_PLAYLIST 106 // Puts uC into deepsleep after playlist is finished + LED-DIMM
#define SLEEP_AFTER_5_TRACKS 107 // Puts uC into deepsleep after five tracks
#define REPEAT_PLAYLIST 110 // Changes active playmode to endless-loop (for a playlist)
#define REPEAT_TRACK 111 // Changes active playmode to endless-loop (for a single track)
#define DIMM_LEDS_NIGHTMODE 120 // Changes LED-brightness
#define TOGGLE_WIFI_STATUS 130 // Toggles WiFi-status
#define TOGGLE_BLUETOOTH_MODE 140 // Toggles Normal/Bluetooth Mode
#define ENABLE_FTP_SERVER 150 // Enables FTP-server
// RFID-modifcation-types
#define CMD_NOTHING 0 // Do Nothing
#define LOCK_BUTTONS_MOD 100 // Locks all buttons and rotary encoder
#define SLEEP_TIMER_MOD_15 101 // Puts uC into deepsleep after 15 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_30 102 // Puts uC into deepsleep after 30 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_60 103 // Puts uC into deepsleep after 60 minutes + LED-DIMM
#define SLEEP_TIMER_MOD_120 104 // Puts uC into deepsleep after 120 minutes + LED-DIMM
#define SLEEP_AFTER_END_OF_TRACK 105 // Puts uC into deepsleep after track is finished + LED-DIMM
#define SLEEP_AFTER_END_OF_PLAYLIST 106 // Puts uC into deepsleep after playlist is finished + LED-DIMM
#define SLEEP_AFTER_5_TRACKS 107 // Puts uC into deepsleep after five tracks + LED-DIMM
#define REPEAT_PLAYLIST 110 // Changes active playmode to endless-loop (for a playlist)
#define REPEAT_TRACK 111 // Changes active playmode to endless-loop (for a single track)
#define DIMM_LEDS_NIGHTMODE 120 // Changes LED-brightness
#define TOGGLE_WIFI_STATUS 130 // Toggles WiFi-status
#define TOGGLE_BLUETOOTH_MODE 140 // Toggles Normal/Bluetooth Mode
#define ENABLE_FTP_SERVER 150 // Enables FTP-server
#define CMD_PLAYPAUSE 170 // Admin-cmd Play/Pause
#define CMD_PREVTRACK 171 // Admin-cmd Prev Track
#define CMD_NEXTTRACK 172 // Admin-cmd Next Track
#define CMD_FIRSTTRACK 173 // Admin-cmd Prev Track
#define CMD_LASTTRACK 174 // Admin-cmd Next Track
#define CMD_VOLUMEINIT 175 // Set volume to Initial
#define CMD_VOLUMEUP 176 // Set volume up
#define CMD_VOLUMEDOWN 177 // Set volume down
#define CMD_MEASUREBATTERY 178 // Measure battery-voltage
#define CMD_SLEEPMODE 179 // Goto deepsleep
#define CMD_PLAYPAUSE 170 // Command: play/pause
#define CMD_PREVTRACK 171 // Command: previous track
#define CMD_NEXTTRACK 172 // Command: next track
#define CMD_FIRSTTRACK 173 // Command: first track
#define CMD_LASTTRACK 174 // Command: last track
#define CMD_VOLUMEINIT 175 // Command: set volume to initial value
#define CMD_VOLUMEUP 176 // Command: increase volume by 1
#define CMD_VOLUMEDOWN 177 // Command: lower volume by 1
#define CMD_MEASUREBATTERY 178 // Command: Measure battery-voltage
#define CMD_SLEEPMODE 179 // Command: Go to deepsleep
// Repeat-Modes
#define NO_REPEAT 0 // No repeat
#define TRACK 1 // Repeat current track (infinite loop)
#define PLAYLIST 2 // Repeat whole playlist (infinite loop)
#define TRACK_N_PLAYLIST 3 // Repeat both (infinite loop)
// Repeat-Modes
#define NO_REPEAT 0 // No repeat
#define TRACK 1 // Repeat current track (infinite loop)
#define PLAYLIST 2 // Repeat whole playlist (infinite loop)
#define TRACK_N_PLAYLIST 3 // Repeat both (infinite loop)
#endif
Loading…
Cancel
Save