Browse Source

Small fixes, description

master
Torsten Stauder 5 years ago
parent
commit
89d1aa2831
  1. 16
      README.md
  2. 25
      src/main.cpp

16
README.md

@ -1,7 +1,7 @@
# Tonuino based on ESP32 with I2S-DAC-support # Tonuino based on ESP32 with I2S-DAC-support
## Disclaimer ## Disclaimer
This is a **fork** of the popular [Tonuino-project](https://github.com/xfjx/TonUINO) which means, that it only shares the basic concept of controlling music-play by RFID-tags and buttons. **Said this I want to make clear, that the code-basis is completely different**. So there might be features, that are supported by my fork whereas others are missing or implemented different. For sure both share that it's non-profit, DIY and developed on [Arduino](https://www.arduino.cc/.
This is a **fork** of the popular [Tonuino-project](https://github.com/xfjx/TonUINO) which means, that it only shares the basic concept of controlling music-play by RFID-tags and buttons. **Said this I want to make clear, that the code-basis is completely different**. So there might be features, that are supported by my fork whereas others are missing or implemented different. For sure both share that it's non-profit, DIY and developed on [Arduino](https://www.arduino.cc/).
**Please note: This project is still under development. So it's not yet feature-complete (e.g. webinterface is missing).** **Please note: This project is still under development. So it's not yet feature-complete (e.g. webinterface is missing).**
@ -11,7 +11,7 @@ The original project makes use of microcontrollers (uC) like Arduino nano (which
The core of my implementation is based on the popular [ESP32 by Espressif](https://www.espressif.com/en/products/hardware/esp32/overview). Having WiFi-support out-of-the-box makes it possible to provide further features like an integrated FTP-server (to feed the player with music), smarthome-integration by using MQTT and webradio. However, my aim was to port the project on a modular base. Said this music-decoding takes place in software with a dedicated uSD-card and music-output is done via I2S-protocol. I did all my tests on [Adafruit's MAX98357A](https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp/pinouts). Hopefully, not only in theory, other DACs can be used as well (has to support 3.3 V-level). The core of my implementation is based on the popular [ESP32 by Espressif](https://www.espressif.com/en/products/hardware/esp32/overview). Having WiFi-support out-of-the-box makes it possible to provide further features like an integrated FTP-server (to feed the player with music), smarthome-integration by using MQTT and webradio. However, my aim was to port the project on a modular base. Said this music-decoding takes place in software with a dedicated uSD-card and music-output is done via I2S-protocol. I did all my tests on [Adafruit's MAX98357A](https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp/pinouts). Hopefully, not only in theory, other DACs can be used as well (has to support 3.3 V-level).
## Basic concept/handling ## Basic concept/handling
The basic idea of Tonuino (and my fork, respectively) is to provide a way, to use the Arduino-platform for a music-control-concept that is derived from the popular Toniebox. This basically means that RFID-tags are used to direct a music-player. Toniebox is based on cloud, Tonuino on a local SD-card. 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.
The basic idea of Tonuino (and my fork, respectively) is to provide a way, to use the Arduino-platform for a music-control-concept that supports locally stored music-files instead of being cloud-dependend. 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.
## Hardware-setup ## Hardware-setup
So it's about time to have a look at the hardware I used. It's a ESP32 on a development-board that more or less looks like [this](https://docs.zerynth.com/latest/official/board.zerynth.nodemcu_esp32/docs/index.html). If ordered in China (Aliexpress, eBay e.g.) it's pretty cheap (around 4€) but even in Europe it's only around 8€. Make sure to install the drivers for the USB/Serial-chip (CP2102 e.g.). So it's about time to have a look at the hardware I used. It's a ESP32 on a development-board that more or less looks like [this](https://docs.zerynth.com/latest/official/board.zerynth.nodemcu_esp32/docs/index.html). If ordered in China (Aliexpress, eBay e.g.) it's pretty cheap (around 4€) but even in Europe it's only around 8€. Make sure to install the drivers for the USB/Serial-chip (CP2102 e.g.).
@ -31,7 +31,7 @@ Most of them can be ordered cheaper directly in China. It's just a give an short
I recommend Microsoft's [Visual Studio Code](https://code.visualstudio.com/) alongside with [Platformio Plugin](https://platformio.org/install/ide?install=vscode.) Since my project on Github contains [platformio.ini](platformio.ini), libraries used should be fetched automatically. Please note: if you use another ESP32-develboard (Lolin32 e.g.) you might have to change "env:" in platformio.ini to the corresponding value. Documentation can be found [here](https://docs.platformio.org/en/latest/projectconf.html). After that it might be necessary to adjust the names of the GPIO-pins in the upper #define-section of my code. I recommend Microsoft's [Visual Studio Code](https://code.visualstudio.com/) alongside with [Platformio Plugin](https://platformio.org/install/ide?install=vscode.) Since my project on Github contains [platformio.ini](platformio.ini), libraries used should be fetched automatically. Please note: if you use another ESP32-develboard (Lolin32 e.g.) you might have to change "env:" in platformio.ini to the corresponding value. Documentation can be found [here](https://docs.platformio.org/en/latest/projectconf.html). After that it might be necessary to adjust the names of the GPIO-pins in the upper #define-section of my code.
## Wiring ## Wiring
A lot of wiring is needed to get it working. After my first experients I soldered the stuff to avoid wild-west-cabling. Feel free to design your own PCBs.
A lot of wiring is necessary to get Tonuino working. After my first experients I soldered the stuff in order to avoid wild-west-cabling. Feel free to design your own PCB(s).
| ESP32 (GPIO) | Hardware | Pin | Comment | | ESP32 (GPIO) | Hardware | Pin | Comment |
| ------------- | --------------------- | ------ | ------------------------------------------------------------ | | ------------- | --------------------- | ------ | ------------------------------------------------------------ |
@ -69,12 +69,12 @@ A lot of wiring is needed to get it working. After my first experients I soldere
| 12 | Neopixel | DI | | | 12 | Neopixel | DI | |
| 17 | BC337 (via R5) | Base | Don't forget R5! | | 17 | BC337 (via R5) | Base | Don't forget R5! |
Optionally, GPIO 17 can be used to drive an NPN-transistor (BC337-40) that pulls a p-channel MOSFET (IRF9520) to GND in order to switch on/off 5V-current. Transistor-circuit is described [here](https://dl6gl.de/schalten-mit-transistoren): Just have a look at Abb. 4. Values of the resistors I used: R1: 10k, R2: omitted(!), R4: 10k, R5: 4,7k
Optionally, GPIO 17 can be used to drive a NPN-transistor (BC337-40) that pulls a p-channel MOSFET (IRF9520) to GND in order to switch on/off 5V-current. Transistor-circuit is described [here](https://dl6gl.de/schalten-mit-transistoren): Just have a look at Abb. 4. Values of the resistors I used: R1: 10k, R2: omitted(!), R4: 10k, R5: 4,7k
## Prerequisites ## Prerequisites
* for debugging-purposes serialDebug can be set (before compiling) to ERROR, NOTICE, INFO or DEBUG. * for debugging-purposes serialDebug can be set (before compiling) to ERROR, NOTICE, INFO or DEBUG.
* make decision, if MQTT should be enabled (enableMqtt) * make decision, if MQTT should be enabled (enableMqtt)
* if yes, set the IP of the MQTT-server and check the MQTT-topics (states and commands)
* if yes, set the IP of the MQTT-server accordingly and check the MQTT-topics (states and commands)
* in setup() RFID-cards can be statically linked to an action/file. Everything is stored in NVS. * in setup() RFID-cards can be statically linked to an action/file. Everything is stored in NVS.
* set NUM_LEDS to the LED-number of your Neopixel-ring. * set NUM_LEDS to the LED-number of your Neopixel-ring.
* please note: by using audiobook-mode any playlist-savings will be overwritten with every start unless the RFID-cards in setup() are commented out. Main way to link RFID to an action will be a webservice (still under development) * please note: by using audiobook-mode any playlist-savings will be overwritten with every start unless the RFID-cards in setup() are commented out. Main way to link RFID to an action will be a webservice (still under development)
@ -82,6 +82,7 @@ Optionally, GPIO 17 can be used to drive an NPN-transistor (BC337-40) that pulls
## Starting Tonuino-ESP32 first time ## Starting Tonuino-ESP32 first time
After plugging in it takes a few seconds until neopixel indicates that Tonuino is ready (by four (slow) rotating LEDs). If uC was not able to connect to WiFi, an access-point (named Tonuino) is opened and after connecting this WiFi, a [configuration-Interface](http://192.168.4.1) is available. Enter WiFI-credentials, save them and restart the uC. Then reconnect to your "regular" WiFi. Place your favourite RFID-tag next to the RFID-reader and the music should start to play. While the playlist is generated, fast-rotating LEDs are shown. The more tracks a playlist contains the longer this step takes. After plugging in it takes a few seconds until neopixel indicates that Tonuino is ready (by four (slow) rotating LEDs). If uC was not able to connect to WiFi, an access-point (named Tonuino) is opened and after connecting this WiFi, a [configuration-Interface](http://192.168.4.1) is available. Enter WiFI-credentials, save them and restart the uC. Then reconnect to your "regular" WiFi. Place your favourite RFID-tag next to the RFID-reader and the music should start to play. While the playlist is generated, fast-rotating LEDs are shown. The more tracks a playlist contains the longer this step takes.
In setup() there's a section that hardcodes RFID-card-IDs to actions. Just apply a new card to the reader and have a look at it's ID in serial console. This ID has to be used to link it to a file/folder and playmode. In future this won't be necessary any more as this step can be perfomed more comfortable using a webinterface.
## Interacting with Tonuino ## Interacting with Tonuino
### Playmodes ### Playmodes
@ -158,4 +159,7 @@ As already described in the modify-section, there are different sleepmodes avail
Everything that can be controlled via RFID-tags and buttons, can also be controlled via MQTT. All manual interactions (buttons, RFID-tags) are also sent to MQTT in parallel, so everything is always in-sync (unless Wifi/MQTT-connection is broken). In my home-setup I'm using [openHAB](https://www.openhab.org/) to encapsulate MQTT into a nice GUI, that's accessible via APP + web. ToDo: Publish sample-configurations for openHAB. Everything that can be controlled via RFID-tags and buttons, can also be controlled via MQTT. All manual interactions (buttons, RFID-tags) are also sent to MQTT in parallel, so everything is always in-sync (unless Wifi/MQTT-connection is broken). In my home-setup I'm using [openHAB](https://www.openhab.org/) to encapsulate MQTT into a nice GUI, that's accessible via APP + web. ToDo: Publish sample-configurations for openHAB.
### Supported file/stream-types ### Supported file/stream-types
Please refer [ESP32-audioI2S](https://github.com/schreibfaul1/ESP32-audioI2S), as this is the lib I integrated for music-decoding.
Please refer [ESP32-audioI2S](https://github.com/schreibfaul1/ESP32-audioI2S), as this is the lib I integrated for music-decoding.
## Smarthome
As already described, MQTT is supported. In order to use it it's necessary to run a MQTT-broker; [Mosquitto](https://mosquitto.org/) for instance. After connecting to it, Tonuino subscribes to all command-topics. State-topics are used to push states to the broker in order to inform others if anything changed (change of volume, new playlist, new track... name it). Others, like openHAB, subscribe to state-topics end send commands via command-topics. So it's not just limited to openHAB. It's just necessary to use a platform, that supports MQTT.

25
src/main.cpp

@ -67,7 +67,7 @@ char logBuf[160]; // Buffer for all log-messag
#define LED_PIN 12 #define LED_PIN 12
// Neopixel-configuration // Neopixel-configuration
#define NUM_LEDS 16
#define NUM_LEDS 24
#define CHIPSET WS2811 #define CHIPSET WS2811
#define COLOR_ORDER GRB #define COLOR_ORDER GRB
@ -554,7 +554,7 @@ uint8_t getRepeatMode(void) {
return PLAYLIST; return PLAYLIST;
} else if (!playProperties.repeatPlaylist && playProperties.repeatCurrentTrack) { } else if (!playProperties.repeatPlaylist && playProperties.repeatCurrentTrack) {
return TRACK; return TRACK;
} else if (!playProperties.repeatPlaylist && !playProperties.repeatCurrentTrack) {
} else {
return NO_REPEAT; return NO_REPEAT;
} }
} }
@ -1455,18 +1455,19 @@ void showLed(void *parameter) {
switch (playProperties.playMode) { switch (playProperties.playMode) {
case NO_PLAYLIST: // If no playlist is active (idle) case NO_PLAYLIST: // If no playlist is active (idle)
if (hlastVolume == currentVolume && lastLedBrightness == ledBrightness) { if (hlastVolume == currentVolume && lastLedBrightness == ledBrightness) {
double c = NUM_LEDS * 0.75;
for (uint8_t i=0; i < NUM_LEDS; i++) { for (uint8_t i=0; i < NUM_LEDS; i++) {
FastLED.clear(); FastLED.clear();
if (i == 0) { if (i == 0) {
leds[0] = CRGB::White; leds[0] = CRGB::White;
leds[NUM_LEDS/4] = CRGB::White; leds[NUM_LEDS/4] = CRGB::White;
leds[NUM_LEDS/2] = CRGB::White; leds[NUM_LEDS/2] = CRGB::White;
leds[NUM_LEDS*3 / NUM_LEDS*4] = CRGB::White;
leds[(int) c] = CRGB::White;
} else { } else {
leds[i % NUM_LEDS] = CRGB::White; leds[i % NUM_LEDS] = CRGB::White;
leds[(i+NUM_LEDS/4) % NUM_LEDS] = CRGB::White; leds[(i+NUM_LEDS/4) % NUM_LEDS] = CRGB::White;
leds[(i+NUM_LEDS/2) % NUM_LEDS] = CRGB::White; leds[(i+NUM_LEDS/2) % NUM_LEDS] = CRGB::White;
leds[(i+NUM_LEDS*3 / NUM_LEDS*4) % NUM_LEDS] = CRGB::White;
leds[(i+(int) c) % NUM_LEDS] = CRGB::White;
} }
FastLED.show(); FastLED.show();
for (uint8_t i=0; i<=50; i++) { for (uint8_t i=0; i<=50; i++) {
@ -2111,7 +2112,7 @@ void handleWifiSetup() {
loggerNl(logBuf, LOGLEVEL_INFO); loggerNl(logBuf, LOGLEVEL_INFO);
if (server.argName(i) == "ssid") { if (server.argName(i) == "ssid") {
snprintf(logBuf, sizeof(logBuf) / sizeof(logBuf[0]), "%S: %s", (char *) FPSTR(savedSsidInNvs), server.arg(i).c_str());
snprintf(logBuf, sizeof(logBuf) / sizeof(logBuf[0]), "%s: %s", (char *) FPSTR(savedSsidInNvs), server.arg(i).c_str());
loggerNl(logBuf, LOGLEVEL_NOTICE); loggerNl(logBuf, LOGLEVEL_NOTICE);
prefsSettings.putString("SSID", server.arg(i)); prefsSettings.putString("SSID", server.arg(i));
} else if (server.argName(i) == "pw") { } else if (server.argName(i) == "pw") {
@ -2217,15 +2218,17 @@ void setup() {
playProperties.playlistFinished = true; playProperties.playlistFinished = true;
// Examples for serialized RFID-actions that are stored in NVS // Examples for serialized RFID-actions that are stored in NVS
// #<file/folder>#<startPlayPositionInBytes>#<playmode>#<trackNumberToStartWith>
// Don't forget to comment this section out for regular usage as it probably overwrites saved states in mode audiobook
prefsRfid.putString("215123125075", "#/mp3/Kinderlieder#0#6#0"); prefsRfid.putString("215123125075", "#/mp3/Kinderlieder#0#6#0");
prefsRfid.putString("009236075184", "#/Aura - Avoure.mp3#0#3#0"); prefsRfid.putString("009236075184", "#/Aura - Avoure.mp3#0#3#0");
prefsRfid.putString("073022077184", "#/kurz#0#7#0"); prefsRfid.putString("073022077184", "#/kurz#0#7#0");
prefsRfid.putString("169239075184", "#http://radio.koennmer.net/evosonic.mp3#0#8#0"); prefsRfid.putString("169239075184", "#http://radio.koennmer.net/evosonic.mp3#0#8#0");
prefsRfid.putString("244105171042", "#0#0#111#0");
prefsRfid.putString("075081176028", "#0#0#106#0");
prefsRfid.putString("212216120042", "#0#0#105#0");
prefsRfid.putString("020059140043", "#0#0#111#0");
prefsRfid.putString("228064156042", "#0#0#110#0");
prefsRfid.putString("244105171042", "#0#0#111#0"); // modification-card (repeat track)
prefsRfid.putString("075081176028", "#0#0#106#0"); // modification-card (sleep at end of playlist)
prefsRfid.putString("212216120042", "#0#0#105#0"); // modification-card (sleep at end of track)
prefsRfid.putString("020059140043", "#0#0#111#0"); // modification-card (repeat current track)
prefsRfid.putString("228064156042", "#0#0#110#0"); // modification-card (repeat playlist)
prefsRfid.putString("018030087052", "#http://shouthost.com.19.streams.bassdrive.com:8200#0#8#0"); prefsRfid.putString("018030087052", "#http://shouthost.com.19.streams.bassdrive.com:8200#0#8#0");
prefsRfid.putString("182146124043", "#http://ibizaglobalradio.streaming-pro.com:8024#0#8#0"); prefsRfid.putString("182146124043", "#http://ibizaglobalradio.streaming-pro.com:8024#0#8#0");
prefsRfid.putString("018162219052", "#http://stream2.friskyradio.com:8000/frisky_mp3_hi#0#8#0"); prefsRfid.putString("018162219052", "#http://stream2.friskyradio.com:8000/frisky_mp3_hi#0#8#0");
@ -2287,7 +2290,7 @@ void setup() {
uint8_t nvsNLedBrightness = prefsSettings.getUChar("nLedBrightness", 0); uint8_t nvsNLedBrightness = prefsSettings.getUChar("nLedBrightness", 0);
if (nvsNLedBrightness) { if (nvsNLedBrightness) {
nightLedBrightness = nvsNLedBrightness; nightLedBrightness = nvsNLedBrightness;
snprintf(logBuf, sizeof(logBuf) / sizeof(logBuf[0]), "%S: %d", (char *) FPSTR(loadedInitialBrightnessForNmFromNvs), nvsNLedBrightness);
snprintf(logBuf, sizeof(logBuf) / sizeof(logBuf[0]), "%s: %d", (char *) FPSTR(loadedInitialBrightnessForNmFromNvs), nvsNLedBrightness);
loggerNl(logBuf, LOGLEVEL_INFO); loggerNl(logBuf, LOGLEVEL_INFO);
} else { } else {
prefsSettings.putUChar("nLedBrightness", nightLedBrightness); prefsSettings.putUChar("nLedBrightness", nightLedBrightness);

Loading…
Cancel
Save