Browse Source

Support for reverse Neopixel-signaling added

master
Torsten Stauder 5 years ago
parent
commit
870421a2df
  1. 8
      README.md
  2. 91
      src/main.cpp

8
README.md

@ -1,5 +1,8 @@
# Tonuino based on ESP32 with I2S-DAC-support # Tonuino based on ESP32 with I2S-DAC-support
## NEWS
Currently I'm working on a new Tonuino that is completely based on 3.3V. As uC-develboard a Lolin32 is used and it's (optionally) battery-powered. So stay tuned...
## 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 a music-player by RFID-tags and buttons. **Said this I want to rule out, that the code-basis is completely different and developed by me**. So there might be features, that are supported by my fork whereas others are missing or implemented differently. 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 a music-player by RFID-tags and buttons. **Said this I want to rule out, that the code-basis is completely different and developed by me**. So there might be features, that are supported by my fork whereas others are missing or implemented differently. For sure both share that it's non-profit, DIY and developed on [Arduino](https://www.arduino.cc/).
@ -153,6 +156,9 @@ Indicates different things. Don't forget configuration of number of LEDs via #de
* paused: track-progress-LEDs coloured orange * paused: track-progress-LEDs coloured orange
* rewind: if single-track-loop is activated a LED-rewind is performed when restarting the given track * rewind: if single-track-loop is activated a LED-rewind is performed when restarting the given track
Please note: some Neopixels use a reversed addressing which leads to the 'problem', that all effects are shown
counter clockwise. If you want to change that behaviour, just enable `NEOPIXEL_REVERSE_ROTATION`.
### Buttons ### Buttons
Some buttons have different actions if pressed long or short. Minimum duration for long press in ms is defined by `intervalToLongPress`. Some buttons have different actions if pressed long or short. 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 (short): previous track / beginning of the first track if pressed while first track is playing
@ -201,4 +207,4 @@ Please refer [ESP32-audioI2S](https://github.com/schreibfaul1/ESP32-audioI2S), a
As all assignments between RFID-IDs and actions (playmode, file to play...) is saved in ESP's NVS, the problem is that it's all gone when the ESP is broken. So that's where a backup comes into play. So every time you change or add a new assignment between a RFID-tag and an action via GUI, a backup-file is saved on the uSD-card. The file's name can be changed via `backupFile`. Again using the GUI you can use the upload-form to import such a file. To be honest: Sometimes I had some issues with Firefox doing this whereas Safari turned out to do it right. Don't know why :-(. As all assignments between RFID-IDs and actions (playmode, file to play...) is saved in ESP's NVS, the problem is that it's all gone when the ESP is broken. So that's where a backup comes into play. So every time you change or add a new assignment between a RFID-tag and an action via GUI, a backup-file is saved on the uSD-card. The file's name can be changed via `backupFile`. Again using the GUI you can use the upload-form to import such a file. To be honest: Sometimes I had some issues with Firefox doing this whereas Safari turned out to do it right. Don't know why :-(.
## Smarthome (optional) ## Smarthome (optional)
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. For [further informations refer](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/openHAB).
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. For further informations refer the [subfolder](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/openHAB).

91
src/main.cpp

@ -1,7 +1,8 @@
// Define modules to compile: // Define modules to compile:
//#define MQTT_ENABLE
#define MQTT_ENABLE
#define FTP_ENABLE #define FTP_ENABLE
#define NEOPIXEL_ENABLE // Don't forget configuration of NUM_LEDS #define NEOPIXEL_ENABLE // Don't forget configuration of NUM_LEDS
//#define NEOPIXEL_REVERSE_ROTATION // Some Neopixels are adressed counter-clockwise. This can be configured here.
#include <ESP32Encoder.h> #include <ESP32Encoder.h>
#include "Arduino.h" #include "Arduino.h"
@ -85,7 +86,7 @@ char logBuf[160]; // Buffer for all log-messag
// Neopixel-configuration // Neopixel-configuration
#ifdef NEOPIXEL_ENABLE #ifdef NEOPIXEL_ENABLE
#define NUM_LEDS 16 // number of LEDs
#define NUM_LEDS 24 // number of LEDs
#define CHIPSET WS2812B // type of Neopixel #define CHIPSET WS2812B // type of Neopixel
#define COLOR_ORDER GRB #define COLOR_ORDER GRB
#endif #endif
@ -1515,6 +1516,18 @@ void rfidScanner(void *parameter) {
// This task handles everything for Neopixel-visualisation // This task handles everything for Neopixel-visualisation
#ifdef NEOPIXEL_ENABLE #ifdef NEOPIXEL_ENABLE
// Switches Neopixel-addressing from clockwise to counter clockwise (and vice versa)
uint8_t ledAddress(uint8_t number) {
#ifdef NEOPIXEL_REVERSE_ROTATION
return NUM_LEDS-1-number;
#else
return number;
#endif
}
void showLed(void *parameter) { void showLed(void *parameter) {
static uint8_t hlastVolume = currentVolume; static uint8_t hlastVolume = currentVolume;
static uint8_t lastPos = playProperties.currentRelPos; static uint8_t lastPos = playProperties.currentRelPos;
@ -1536,23 +1549,23 @@ void showLed(void *parameter) {
FastLED.setBrightness(ledBrightness); FastLED.setBrightness(ledBrightness);
for (;;) { for (;;) {
if (!bootComplete) { // Rotates red unless boot isn't complete
if (!bootComplete) { // Rotates orange unless boot isn't complete
FastLED.clear(); FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) { for (uint8_t led = 0; led < NUM_LEDS; led++) {
if (showEvenError) { if (showEvenError) {
if (led % 2 == 0) {
if (ledAddress(led) % 2 == 0) {
if (millis() <= 10000) { if (millis() <= 10000) {
leds[led] = CRGB::Orange;
leds[ledAddress(led)] = CRGB::Orange;
} else { } else {
leds[led] = CRGB::Red;
leds[ledAddress(led)] = CRGB::Red;
} }
} }
} else { } else {
if (millis() >= 10000) { // Flashes red after 10s (will remain forever if SD cannot be mounted) if (millis() >= 10000) { // Flashes red after 10s (will remain forever if SD cannot be mounted)
leds[led] = CRGB::Red;
leds[ledAddress(led)] = CRGB::Red;
} else { } else {
if (led % 2 == 1) {
leds[led] = CRGB::Orange;
if (ledAddress(led) % 2 == 1) {
leds[ledAddress(led)] = CRGB::Orange;
} }
} }
} }
@ -1572,7 +1585,7 @@ void showLed(void *parameter) {
if (!buttons[3].currentState) { if (!buttons[3].currentState) {
FastLED.clear(); FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) { for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[led] = CRGB::Red;
leds[ledAddress(led)] = CRGB::Red;
if (buttons[3].currentState) { if (buttons[3].currentState) {
FastLED.clear(); FastLED.clear();
FastLED.show(); FastLED.show();
@ -1591,7 +1604,7 @@ void showLed(void *parameter) {
FastLED.clear(); FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) { for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[led] = CRGB::Red;
leds[ledAddress(led)] = CRGB::Red;
} }
FastLED.show(); FastLED.show();
vTaskDelay(portTICK_RATE_MS * 200); vTaskDelay(portTICK_RATE_MS * 200);
@ -1603,7 +1616,7 @@ void showLed(void *parameter) {
FastLED.clear(); FastLED.clear();
for (uint8_t led = 0; led < NUM_LEDS; led++) { for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[led] = CRGB::Green;
leds[ledAddress(led)] = CRGB::Green;
} }
FastLED.show(); FastLED.show();
vTaskDelay(portTICK_RATE_MS * 400); vTaskDelay(portTICK_RATE_MS * 400);
@ -1616,7 +1629,7 @@ void showLed(void *parameter) {
FastLED.clear(); FastLED.clear();
for (int led = 0; led < numLedsToLight; led++) { // (Inverse) color-gradient from green (85) back to (still) red (245) using unsigned-cast for (int led = 0; led < numLedsToLight; led++) { // (Inverse) color-gradient from green (85) back to (still) red (245) using unsigned-cast
leds[led].setHue((uint8_t) (85 - ((double) 95 / NUM_LEDS) * led));
leds[ledAddress(led)].setHue((uint8_t) (85 - ((double) 95 / NUM_LEDS) * led));
} }
FastLED.show(); FastLED.show();
@ -1635,7 +1648,7 @@ void showLed(void *parameter) {
if (showRewind) { if (showRewind) {
showRewind = false; showRewind = false;
for (uint8_t i=NUM_LEDS-1; i>0; i--) { for (uint8_t i=NUM_LEDS-1; i>0; i--) {
leds[i] = CRGB::Black;
leds[ledAddress(i)] = CRGB::Black;
FastLED.show(); FastLED.show();
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
break; break;
@ -1651,7 +1664,7 @@ void showLed(void *parameter) {
uint8_t numLedsToLight = map(playProperties.currentTrackNumber, 0, playProperties.numberOfTracks-1, 0, NUM_LEDS); uint8_t numLedsToLight = map(playProperties.currentTrackNumber, 0, playProperties.numberOfTracks-1, 0, NUM_LEDS);
FastLED.clear(); FastLED.clear();
for (uint8_t i=0; i < numLedsToLight; i++) { for (uint8_t i=0; i < numLedsToLight; i++) {
leds[i] = CRGB::Blue;
leds[ledAddress(i)] = CRGB::Blue;
FastLED.show(); FastLED.show();
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
break; break;
@ -1669,7 +1682,7 @@ void showLed(void *parameter) {
} }
for (uint8_t i=numLedsToLight; i>0; i--) { for (uint8_t i=numLedsToLight; i>0; i--) {
leds[i-1] = CRGB::Black;
leds[ledAddress(i)-1] = CRGB::Black;
FastLED.show(); FastLED.show();
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
break; break;
@ -1683,18 +1696,18 @@ 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) {
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 (ledAddress(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/4*3] = CRGB::White; leds[NUM_LEDS/4*3] = CRGB::White;
} else { } else {
leds[i % 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/4*3) % NUM_LEDS] = CRGB::White;
leds[ledAddress(i) % NUM_LEDS] = CRGB::White;
leds[(ledAddress(i)+NUM_LEDS/4) % NUM_LEDS] = CRGB::White;
leds[(ledAddress(i)+NUM_LEDS/2) % NUM_LEDS] = CRGB::White;
leds[(ledAddress(i)+NUM_LEDS/4*3) % NUM_LEDS] = CRGB::White;
} }
FastLED.show(); FastLED.show();
for (uint8_t i=0; i<=50; i++) { for (uint8_t i=0; i<=50; i++) {
@ -1712,16 +1725,16 @@ void showLed(void *parameter) {
ledBusyShown = true; ledBusyShown = true;
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 (ledAddress(i) == 0) {
leds[0] = CRGB::BlueViolet; leds[0] = CRGB::BlueViolet;
leds[NUM_LEDS/4] = CRGB::BlueViolet; leds[NUM_LEDS/4] = CRGB::BlueViolet;
leds[NUM_LEDS/2] = CRGB::BlueViolet; leds[NUM_LEDS/2] = CRGB::BlueViolet;
leds[NUM_LEDS/4*3] = CRGB::BlueViolet; leds[NUM_LEDS/4*3] = CRGB::BlueViolet;
} else { } else {
leds[i % NUM_LEDS] = CRGB::BlueViolet;
leds[(i+NUM_LEDS/4) % NUM_LEDS] = CRGB::BlueViolet;
leds[(i+NUM_LEDS/2) % NUM_LEDS] = CRGB::BlueViolet;
leds[(i+NUM_LEDS/4*3) % NUM_LEDS] = CRGB::BlueViolet;
leds[ledAddress(i) % NUM_LEDS] = CRGB::BlueViolet;
leds[(ledAddress(i)+NUM_LEDS/4) % NUM_LEDS] = CRGB::BlueViolet;
leds[(ledAddress(i)+NUM_LEDS/2) % NUM_LEDS] = CRGB::BlueViolet;
leds[(ledAddress(i)+NUM_LEDS/4*3) % NUM_LEDS] = CRGB::BlueViolet;
} }
FastLED.show(); FastLED.show();
if (playProperties.playMode != BUSY) { if (playProperties.playMode != BUSY) {
@ -1754,14 +1767,14 @@ void showLed(void *parameter) {
FastLED.clear(); FastLED.clear();
for (uint8_t led = 0; led < numLedsToLight; led++) { for (uint8_t led = 0; led < numLedsToLight; led++) {
if (lockControls) { if (lockControls) {
leds[led] = CRGB::Red;
leds[ledAddress(led)] = CRGB::Red;
} else if (!playProperties.pausePlay) { // Hue-rainbow } else if (!playProperties.pausePlay) { // Hue-rainbow
leds[led].setHue((uint8_t) (((double) 255 / NUM_LEDS) * led));
leds[ledAddress(led)].setHue((uint8_t) (((double) 255 / NUM_LEDS) * led));
} else if (playProperties.pausePlay) { } else if (playProperties.pausePlay) {
leds[led % NUM_LEDS] = CRGB::Orange;
leds[(led+NUM_LEDS/4) % NUM_LEDS] = CRGB::Orange;
leds[(led+NUM_LEDS/2) % NUM_LEDS] = CRGB::Orange;
leds[(led+NUM_LEDS/4*3) % NUM_LEDS] = CRGB::Orange;
leds[ledAddress(led) % NUM_LEDS] = CRGB::Orange;
leds[(ledAddress(led)+NUM_LEDS/4) % NUM_LEDS] = CRGB::Orange;
leds[(ledAddress(led)+NUM_LEDS/2) % NUM_LEDS] = CRGB::Orange;
leds[(ledAddress(led)+NUM_LEDS/4*3) % NUM_LEDS] = CRGB::Orange;
break; break;
} }
} }
@ -1777,14 +1790,14 @@ void showLed(void *parameter) {
ledPosWebstream = 0; ledPosWebstream = 0;
} }
if (lockControls) { if (lockControls) {
leds[ledPosWebstream] = CRGB::Red;
leds[(ledPosWebstream+NUM_LEDS/2) % NUM_LEDS] = CRGB::Red;
leds[ledAddress(ledPosWebstream)] = CRGB::Red;
leds[(ledAddress(ledPosWebstream)+NUM_LEDS/2) % NUM_LEDS] = CRGB::Red;
} else if (!playProperties.pausePlay) { } else if (!playProperties.pausePlay) {
leds[ledPosWebstream].setHue(webstreamColor);
leds[(ledPosWebstream+NUM_LEDS/2) % NUM_LEDS].setHue(webstreamColor++);
leds[ledAddress(ledPosWebstream)].setHue(webstreamColor);
leds[(ledAddress(ledPosWebstream)+NUM_LEDS/2) % NUM_LEDS].setHue(webstreamColor++);
} else if (playProperties.pausePlay) { } else if (playProperties.pausePlay) {
leds[ledPosWebstream] = CRGB::Orange;
leds[(ledPosWebstream+NUM_LEDS/2) % NUM_LEDS] = CRGB::Orange;
leds[ledAddress(ledPosWebstream)] = CRGB::Orange;
leds[(ledAddress(ledPosWebstream)+NUM_LEDS/2) % NUM_LEDS] = CRGB::Orange;
} }
} }
} }

Loading…
Cancel
Save