Browse Source

Added: Bat-voltage-visualisation and RFID-recall

master
Torsten Stauder 5 years ago
parent
commit
00b8fe03c3
  1. 6
      README.md
  2. 22
      html/website.html
  3. 22
      html/website_EN.html
  4. 6
      src/logmessages.h
  5. 6
      src/logmessages_EN.h
  6. 202
      src/main.cpp
  7. 22
      src/websiteMgmt.h
  8. 22
      src/websiteMgmt_EN.h

6
README.md

@ -129,9 +129,10 @@ Keep in mind the RFID-lib I used is intended for default-SPI-pins only (SCK, MIS
* if Neopixel enabled: set NUM_LEDS to the LED-number of your Neopixel-ring and define the Neopixel-type using `#define CHIPSET` * if Neopixel enabled: set NUM_LEDS to the LED-number of your Neopixel-ring and define the Neopixel-type using `#define CHIPSET`
* If you're using Arduino-IDE please make sure to change ESP32's partition-layout to `No OTA (2MB APP/2MB Spiffs)` as otherwise the sketch won't fit into the flash-memory. * If you're using Arduino-IDE please make sure to change ESP32's partition-layout to `No OTA (2MB APP/2MB Spiffs)` as otherwise the sketch won't fit into the flash-memory.
* Please keep in mind that working SD is mandatory. Unless `SD_NOT_MANDATORY_ENABLE` is not set, Tonuino will never fully start up if SD is not working. Only use `SD_NOT_MANDATORY_ENABLE` for debugging as for normal operational mode, not having SD working doesn't make sense. * Please keep in mind that working SD is mandatory. Unless `SD_NOT_MANDATORY_ENABLE` is not set, Tonuino will never fully start up if SD is not working. Only use `SD_NOT_MANDATORY_ENABLE` for debugging as for normal operational mode, not having SD working doesn't make sense.
* If you want to monitor the battery-voltage, make sure to enable `MEASURE_BATTERY_VOLTAGE`. Use a voltage-divider as voltage of a LiPo is way too high for ESP32 (only 3.3V supported!). For my tests I connected VBat with a serial connection of 130k + 390k resistors (VBat--130k--X--390k--GND). X is the measure-point where to connect the GPIO to.
* If you want to monitor the battery-voltage, make sure to enable `MEASURE_BATTERY_VOLTAGE`. Use a voltage-divider as voltage of a LiPo is way too high for ESP32 (only 3.3V supported!). For my tests I connected VBat with a serial connection of 130k + 390k resistors (VBat--130k--X--390k--GND). X is the measure-point where to connect the GPIO to. Please note: via GUI upper and lower voltage for visualisation of battery-voltage (Neopixel) is available. Additional GUI-configurable values are interval (in minutes) for checking battery voltage and the cut off-voltage below whose a warning is shown via Neopixel.
* If you're using a headphone-pcb with 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 to indicate if there's a plug, you can use this signal along with the feature `HEADPHONE_ADJUST_ENABLE` to limit the maximum headphone-voltage automatically. As per default you have to invert this signal and connect it to GPIO22. * If you're using a headphone-pcb with 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 to indicate if there's a plug, you can use this signal along with the feature `HEADPHONE_ADJUST_ENABLE` to limit the maximum headphone-voltage automatically. As per default you have to invert this signal and connect it to GPIO22.
* Enabling `SHUTDOWN_IF_SD_BOOT_FAILS` is really recommended if you run your Tonuino in battery-mode without having a restart-button exposed to the outside of the Tonuino's enclosure. Because otherwise there's no way to restart your Tonuino and the error-state will remain until battery is empty (or you open the enclosure, hehe). * Enabling `SHUTDOWN_IF_SD_BOOT_FAILS` is really recommended if you run your Tonuino in battery-mode without having a restart-button exposed to the outside of the Tonuino's enclosure. Because otherwise there's no way to restart your Tonuino and the error-state will remain until battery is empty (or you open the enclosure, hehe).
* Enabling `PLAY_LAST_RFID_AFTER_REBOOT` will tell Tonuino to remember the last RFID-tag played after reboot. So rebooting Tonuino will end up in autoplay.
* compile and upload the sketch * compile and upload the sketch
## Starting Tonuino-ESP32 first time ## Starting Tonuino-ESP32 first time
@ -216,7 +217,8 @@ Indicates different things. Don't forget configuration of number of LEDs via #de
* buttons locked: track-progress-LEDs coloured red * buttons locked: track-progress-LEDs coloured red
* 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
* (Optional) Undervoltage: flashes three times red if battery-voltage is too low
* (Optional) Undervoltage: flashes three times red if battery-voltage is too low. This voltage-level can be configured via GUI.
* (Optional) Short press of rotary encoder's button provides battery-voltage visualisation via Neopixel. Upper und lower voltage can be adjusted via GUI.
Please note: some Neopixels use a reversed addressing which leads to the 'problem', that all effects are shown 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`. counter clockwise. If you want to change that behaviour, just enable `NEOPIXEL_REVERSE_ROTATION`.

22
html/website.html

@ -180,6 +180,22 @@
<label for="inactivityTime">Deep-Sleep nach Inaktivität (Minuten)</label> <label for="inactivityTime">Deep-Sleep nach Inaktivität (Minuten)</label>
<input type="number" min="1" max="1440" class="form-control" id="inactivityTime" name="inactivityTime" value="%MAX_INACTIVITY%" required> <input type="number" min="1" max="1440" class="form-control" id="inactivityTime" name="inactivityTime" value="%MAX_INACTIVITY%" required>
</div> </div>
<div class="form-group col-md-6">
<label for="warningLowVoltage">(Optional) Spannungsgrenze (Batterie), ab der Warnung auf Neopixel angezeigt wird (z.B. 3.4)</label>
<input type="text" class="form-control" id="warningLowVoltage" name="warningLowVoltage" value="%WARNING_LOW_VOLTAGE%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageIndicatorLow">(Optional) Unterer Akkuspannungslevel (Batterie) für Neopixel-Anzeige (z.B. 3.1)</label>
<input type="text" class="form-control" id="voltageIndicatorLow" name="voltageIndicatorLow" value="%VOLTAGE_INDICATOR_LOW%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageIndicatorHigh">(Optional) Oberer Akkuspannungslevel (Batterie) für Neopixel-Anzeige (z.B. 4.2)</label>
<input type="text" class="form-control" id="voltageIndicatorHigh" name="voltageIndicatorHigh" value="%VOLTAGE_INDICATOR_HIGH%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageCheckInterval">(Optional) Häufigkeit der Spannungsmessung (Batterie) in Minuten</label>
<input type="number" min="1" max="180" class="form-control" id="voltageCheckInterval" name="voltageCheckInterval" value="%VOLTAGE_CHECK_INTERVAL%" required>
</div>
<button type="reset" class="btn btn-secondary">Reset</button> <button type="reset" class="btn btn-secondary">Reset</button>
<button type="submit" class="btn btn-primary">Absenden</button> <button type="submit" class="btn btn-primary">Absenden</button>
</form> </form>
@ -271,7 +287,11 @@
mVolHeadphone: document.getElementById('maxVolumeHeadphone').value, mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,
iBright: document.getElementById('initBrightness').value, iBright: document.getElementById('initBrightness').value,
nBright: document.getElementById('nightBrightness').value, nBright: document.getElementById('nightBrightness').value,
iTime: document.getElementById('inactivityTime').value
iTime: document.getElementById('inactivityTime').value,
vWarning: document.getElementById('warningLowVoltage').value,
vIndLow: document.getElementById('voltageIndicatorLow').value,
vIndHi: document.getElementById('voltageIndicatorHigh').value,
vInt: document.getElementById('voltageCheckInterval').value
} }
}; };
var myJSON = JSON.stringify(myObj); var myJSON = JSON.stringify(myObj);

22
html/website_EN.html

@ -180,6 +180,22 @@
<label for="inactivityTime">Deepsleep after inactivity (minutes)</label> <label for="inactivityTime">Deepsleep after inactivity (minutes)</label>
<input type="number" min="1" max="1440" class="form-control" id="inactivityTime" name="inactivityTime" value="%MAX_INACTIVITY%" required> <input type="number" min="1" max="1440" class="form-control" id="inactivityTime" name="inactivityTime" value="%MAX_INACTIVITY%" required>
</div> </div>
<div class="form-group col-md-6">
<label for="warningLowVoltage">(Optional) Neopixel-warning will indicated below this battery-voltage (e.g. 3.4)</label>
<input type="text" class="form-control" id="warningLowVoltage" name="warningLowVoltage" value="%WARNING_LOW_VOLTAGE%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageIndicatorLow">(Optional) Lower voltage (battery) for Neopixel-visualisation (z.B. 3.1)</label>
<input type="text" class="form-control" id="voltageIndicatorLow" name="voltageIndicatorLow" value="%VOLTAGE_INDICATOR_LOW%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageIndicatorHigh">(Optional) Upper voltage (battery) for Neopixel-visualisation (z.B. 4.2)</label>
<input type="text" class="form-control" id="voltageIndicatorHigh" name="voltageIndicatorHigh" value="%VOLTAGE_INDICATOR_HIGH%" pattern="^\d{1,2}(\.\d{1,3})?" required>
</div>
<div class="form-group col-md-6">
<label for="voltageCheckInterval">(Optional) Interval of battery-measurement (minutes)</label>
<input type="number" min="1" max="180" class="form-control" id="voltageCheckInterval" name="voltageCheckInterval" value="%VOLTAGE_CHECK_INTERVAL%" required>
</div>
<button type="reset" class="btn btn-secondary">Reset</button> <button type="reset" class="btn btn-secondary">Reset</button>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>
@ -271,7 +287,11 @@
mVolHeadphone: document.getElementById('maxVolumeHeadphone').value, mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,
iBright: document.getElementById('initBrightness').value, iBright: document.getElementById('initBrightness').value,
nBright: document.getElementById('nightBrightness').value, nBright: document.getElementById('nightBrightness').value,
iTime: document.getElementById('inactivityTime').value
iTime: document.getElementById('inactivityTime').value,
vWarning: document.getElementById('warningLowVoltage').value,
vIndLow: document.getElementById('voltageIndicatorLow').value,
vIndHi: document.getElementById('voltageIndicatorHigh').value,
vInt: document.getElementById('voltageCheckInterval').value
} }
}; };
var myJSON = JSON.stringify(myObj); var myJSON = JSON.stringify(myObj);

6
src/logmessages.h

@ -145,3 +145,9 @@ static const char voltageTooLow[] PROGMEM = "Batteriespannung niedrig";
static const char sdBootFailedDeepsleep[] PROGMEM = "Bootgang wegen SD fehlgeschlagen. Gehe in Deepsleep..."; static const char sdBootFailedDeepsleep[] PROGMEM = "Bootgang wegen SD fehlgeschlagen. Gehe in Deepsleep...";
static const char wifiEnabledAfterRestart[] PROGMEM = "WLAN wird aktiviert."; static const char wifiEnabledAfterRestart[] PROGMEM = "WLAN wird aktiviert.";
static const char wifiDisabledAfterRestart[] PROGMEM = "WLAN wird deaktiviert."; static const char wifiDisabledAfterRestart[] PROGMEM = "WLAN wird deaktiviert.";
static const char voltageIndicatorLowFromNVS[] PROGMEM = "Unterer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen";
static const char voltageIndicatorHighFromNVS[] PROGMEM = "Oberer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen";
static const char voltageCheckIntervalFromNVS[] PROGMEM = "Zyklus für Spannungsmessung (Batterie) fuer Neopixel-Anzeige aus NVS geladen";
static const char warningLowVoltageFromNVS[] PROGMEM = "Spannungslevel (Batterie) fuer Warnung via Neopixel aus NVS geladen";
static const char unableToRestoreLastRfidFromNVS[] PROGMEM = "Letzte RFID konnte nicht aus NVS geladen werden";
static const char restoredLastRfidFromNVS[] PROGMEM = "Letzte RFID wurde aus NVS geladen";

6
src/logmessages_EN.h

@ -145,3 +145,9 @@ static const char voltageTooLow[] PROGMEM = "Low battery-voltage";
static const char sdBootFailedDeepsleep[] PROGMEM = "Failed to boot due to SD. Will go to deepsleep..."; static const char sdBootFailedDeepsleep[] PROGMEM = "Failed to boot due to SD. Will go to deepsleep...";
static const char wifiEnabledAfterRestart[] PROGMEM = "WiFi will be enabled."; static const char wifiEnabledAfterRestart[] PROGMEM = "WiFi will be enabled.";
static const char wifiDisabledAfterRestart[] PROGMEM = "WiFi will be disabled ."; static const char wifiDisabledAfterRestart[] PROGMEM = "WiFi will be disabled .";
static const char voltageIndicatorLowFromNVS[] PROGMEM = "Restored lower voltage-level for Neopixel-display from NVS";
static const char voltageIndicatorHighFromNVS[] PROGMEM = "Restored upper voltage-level for Neopixel-display from NVS";
static const char voltageCheckIntervalFromNVS[] PROGMEM = "Restored interval of battery-measurement or Neopixel-display from NVS";
static const char warningLowVoltageFromNVS[] PROGMEM = "Restored battery-voltage-level for warning via Neopixel from NVS";
static const char unableToRestoreLastRfidFromNVS[] PROGMEM = "Unable to restore last RFID from NVS";
static const char restoredLastRfidFromNVS[] PROGMEM = "Restored last RFID from NVS";

202
src/main.cpp

@ -7,8 +7,10 @@
#define HEADPHONE_ADJUST_ENABLE // Used to adjust (lower) volume for optional headphone-pcb (refer maxVolumeSpeaker / maxVolumeHeadphone) #define HEADPHONE_ADJUST_ENABLE // Used to adjust (lower) volume for optional headphone-pcb (refer maxVolumeSpeaker / maxVolumeHeadphone)
//#define SINGLE_SPI_ENABLE // If only one SPI-instance should be used instead of two (not yet working!) //#define SINGLE_SPI_ENABLE // If only one SPI-instance should be used instead of two (not yet working!)
#define SHUTDOWN_IF_SD_BOOT_FAILS // Will put ESP to deepsleep if boot fails due to SD. Really recommend this if there's in battery-mode no other way to restart ESP! Interval adjustable via deepsleepTimeAfterBootFails. #define SHUTDOWN_IF_SD_BOOT_FAILS // Will put ESP to deepsleep if boot fails due to SD. Really recommend this if there's in battery-mode no other way to restart ESP! Interval adjustable via deepsleepTimeAfterBootFails.
#define MEASURE_BATTERY_VOLTAGE // Enables battery-measurement via GPIO (ADC) and voltage-divider
//#define PLAY_LAST_RFID_AFTER_REBOOT // When restarting Tonuino, the last RFID that was active before, is recalled and played
//#define MEASURE_BATTERY_VOLTAGE // Enables battery-measurement via GPIO (ADC) and voltage-divider
//#define SD_NOT_MANDATORY_ENABLE // Only for debugging-purposes: Tonuino will also start without mounted SD-card anyway (will only try once to mount it). Will overwrite SHUTDOWN_IF_SD_BOOT_FAILS! //#define SD_NOT_MANDATORY_ENABLE // Only for debugging-purposes: Tonuino will also start without mounted SD-card anyway (will only try once to mount it). Will overwrite SHUTDOWN_IF_SD_BOOT_FAILS!
//#define BLUETOOTH_ENABLE // Doesn't work currently (so don't enable) as there's not enough DRAM available //#define BLUETOOTH_ENABLE // Doesn't work currently (so don't enable) as there's not enough DRAM available
@ -121,12 +123,16 @@ char *logBuf = (char*) calloc(serialLoglength, sizeof(char)); // Buffer for all
// GPIOs (LEDs) // GPIOs (LEDs)
#define LED_PIN 12 // Pin where Neopixel is connected to #define LED_PIN 12 // Pin where Neopixel is connected to
// (optional) Default-voltages for battery-monitoring
float warningLowVoltage = 3.4; // If battery-voltage is >= this value, a cyclic warning will be indicated by Neopixel (can be changed via GUI!)
uint8_t voltageCheckInterval = 10; // How of battery-voltage is measured (in minutes) (can be changed via GUI!)
float voltageIndicatorLow = 3.0; // Lower range for Neopixel-voltage-indication (0 leds) (can be changed via GUI!)
float voltageIndicatorHigh = 4.2; // Upper range for Neopixel-voltage-indication (all leds) (can be changed via GUI!)
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
#define VOLTAGE_READ_PIN 33 // Pin to monitor battery-voltage. Change to 35 if you're using Lolin D32 or Lolin D32 pro #define VOLTAGE_READ_PIN 33 // Pin to monitor battery-voltage. Change to 35 if you're using Lolin D32 or Lolin D32 pro
uint16_t r1 = 391; // First resistor of voltage-divider (kOhms) (measure exact value with multimeter!) uint16_t r1 = 391; // First resistor of voltage-divider (kOhms) (measure exact value with multimeter!)
uint8_t r2 = 128; // Second resistor of voltage-divider (kOhms) (measure exact value with multimeter!) uint8_t r2 = 128; // Second resistor of voltage-divider (kOhms) (measure exact value with multimeter!)
float warningLowVoltage = 3.22; // If battery-voltage is >= this value, a cyclic warning will be indicated by Neopixel
uint8_t voltageCheckInterval = 5; // How of battery-voltage is measured (in minutes)
// Internal values // Internal values
float refVoltage = 3.3; // Operation-voltage of ESP32; don't change! float refVoltage = 3.3; // Operation-voltage of ESP32; don't change!
@ -144,6 +150,10 @@ char *logBuf = (char*) calloc(serialLoglength, sizeof(char)); // Buffer for all
#define COLOR_ORDER GRB #define COLOR_ORDER GRB
#endif #endif
#ifdef PLAY_LAST_RFID_AFTER_REBOOT
bool recoverLastRfid = true;
#endif
// Track-Control // Track-Control
#define STOP 1 // Stop play #define STOP 1 // Stop play
#define PLAY 2 // Start play (currently not used) #define PLAY 2 // Start play (currently not used)
@ -269,6 +279,7 @@ bool wifiNeedsRestart = false;
bool showLedOk = false; bool showLedOk = false;
bool showPlaylistProgress = false; bool showPlaylistProgress = false;
bool showRewind = false; bool showRewind = false;
bool showLedVoltage = false;
#endif #endif
// MQTT // MQTT
#ifdef MQTT_ENABLE #ifdef MQTT_ENABLE
@ -419,6 +430,7 @@ void headphoneVolumeManager(void);
bool isNumber(const char *str); bool isNumber(const char *str);
void loggerNl(const char *str, const uint8_t logLevel); void loggerNl(const char *str, const uint8_t logLevel);
void logger(const char *str, const uint8_t logLevel); void logger(const char *str, const uint8_t logLevel);
float measureBatteryVoltage(void);
#ifdef MQTT_ENABLE #ifdef MQTT_ENABLE
bool publishMqtt(const char *topic, const char *payload, bool retained); bool publishMqtt(const char *topic, const char *payload, bool retained);
#endif #endif
@ -484,13 +496,37 @@ void IRAM_ATTR onTimer() {
} }
#ifdef PLAY_LAST_RFID_AFTER_REBOOT
void storeLastRfidPlayed(char *_rfid) {
prefsSettings.putString("lastRfid", (String) _rfid);
}
void recoverLastRfidPlayed(void) {
if (recoverLastRfid) {
recoverLastRfid = false;
String lastRfidPlayed = prefsSettings.getString("lastRfid", "-1");
if (!lastRfidPlayed.compareTo("-1")) {
loggerNl((char *) FPSTR(unableToRestoreLastRfidFromNVS), LOGLEVEL_INFO);
} else {
char *lastRfid = strdup(lastRfidPlayed.c_str());
xQueueSend(rfidCardQueue, &lastRfid, 0);
snprintf(logBuf, serialLoglength, "%s: %s", (char *) FPSTR(restoredLastRfidFromNVS), lastRfidPlayed.c_str());
loggerNl(logBuf, LOGLEVEL_INFO);
}
}
}
#endif
// Measures voltage of a battery as per interval or after bootup (after allowing a few seconds to settle down) // Measures voltage of a battery as per interval or after bootup (after allowing a few seconds to settle down)
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
void batteryVoltageTester(void) {
if ((millis() - lastVoltageCheckTimestamp >= voltageCheckInterval*60000) || (!lastVoltageCheckTimestamp && millis()>=10000)) {
float measureBatteryVoltage(void) {
float factor = 1 / ((float) r1/(r1+r2)); float factor = 1 / ((float) r1/(r1+r2));
float voltage = ((float) analogRead(VOLTAGE_READ_PIN) / maxAnalogValue) * refVoltage * factor;
return ((float) analogRead(VOLTAGE_READ_PIN) / maxAnalogValue) * refVoltage * factor;
}
void batteryVoltageTester(void) {
if ((millis() - lastVoltageCheckTimestamp >= voltageCheckInterval*60000) || (!lastVoltageCheckTimestamp && millis()>=10000)) {
float voltage = measureBatteryVoltage();
#ifdef NEOPIXEL_ENABLE #ifdef NEOPIXEL_ENABLE
if (voltage <= warningLowVoltage) { if (voltage <= warningLowVoltage) {
snprintf(logBuf, serialLoglength, "%s: (%.2f V)", (char *) FPSTR(voltageTooLow), voltage); snprintf(logBuf, serialLoglength, "%s: (%.2f V)", (char *) FPSTR(voltageTooLow), voltage);
@ -610,8 +646,18 @@ void doButtonActions(void) {
break; break;
case 3: case 3:
//gotoSleep = true;
break;
buttons[i].isPressed = false;
#ifdef MEASURE_BATTERY_VOLTAGE
float voltage = measureBatteryVoltage();
snprintf(logBuf, serialLoglength, "%s: %.2f V", (char *) FPSTR(currentVoltageMsg), voltage);
loggerNl(logBuf, LOGLEVEL_INFO);
showLedVoltage = true;
#ifdef MQTT_ENABLE
char vstr[6];
snprintf(vstr, 6, "%.2f", voltage);
publishMqtt((char *) FPSTR(topicBatteryVoltage), vstr, false);
#endif
#endif
} }
} }
} }
@ -759,7 +805,7 @@ void callback(const char *topic, const byte *payload, uint32_t length) {
else if (strcmp_P(topic, topicTrackCmnd) == 0) { else if (strcmp_P(topic, topicTrackCmnd) == 0) {
char *_rfidId = strdup(receivedString); char *_rfidId = strdup(receivedString);
xQueueSend(rfidCardQueue, &_rfidId, 0); xQueueSend(rfidCardQueue, &_rfidId, 0);
free(_rfidId);
//free(_rfidId);
} }
// Loudness to change? // Loudness to change?
else if (strcmp_P(topic, topicLoudnessCmnd) == 0) { else if (strcmp_P(topic, topicLoudnessCmnd) == 0) {
@ -1702,7 +1748,6 @@ void showLed(void *parameter) {
for (uint8_t led = 0; led < NUM_LEDS; led++) { for (uint8_t led = 0; led < NUM_LEDS; led++) {
leds[ledAddress(led)] = CRGB::Red; leds[ledAddress(led)] = CRGB::Red;
if (buttons[3].currentState) { if (buttons[3].currentState) {
FastLED.clear();
FastLED.show(); FastLED.show();
delay(5); delay(5);
deepSleepManager(); deepSleepManager();
@ -1758,6 +1803,40 @@ void showLed(void *parameter) {
vTaskDelay(portTICK_RATE_MS * 200); vTaskDelay(portTICK_RATE_MS * 200);
} }
} }
if (showLedVoltage) {
showLedVoltage = false;
float currentVoltage = measureBatteryVoltage();
float vDiffIndicatorRange = voltageIndicatorHigh-voltageIndicatorLow;
float vDiffCurrent = currentVoltage-voltageIndicatorLow;
if (vDiffCurrent < 0) { // If voltage is too low or no battery is connected
showLedError = true;
break;
} else {
uint8_t numLedsToLight = ((float) vDiffCurrent/vDiffIndicatorRange) * NUM_LEDS;
FastLED.clear();
for (uint8_t led = 0; led < numLedsToLight; led++) {
if (((float) numLedsToLight / NUM_LEDS) >= 0.6) {
leds[ledAddress(led)] = CRGB::Green;
} else if (((float) numLedsToLight / NUM_LEDS) <= 0.6 && ((float) numLedsToLight / NUM_LEDS) >= 0.3) {
leds[ledAddress(led)] = CRGB::Orange;
} else {
leds[ledAddress(led)] = CRGB::Red;
}
FastLED.show();
vTaskDelay(portTICK_RATE_MS*20);
}
for (uint8_t i=0; i<=100; i++) {
if (hlastVolume != currentVolume || showLedError || showLedOk || !buttons[3].currentState) {
break;
}
vTaskDelay(portTICK_RATE_MS*20);
}
}
}
#endif #endif
if (hlastVolume != currentVolume) { // If volume has been changed if (hlastVolume != currentVolume) { // If volume has been changed
@ -1805,7 +1884,7 @@ void showLed(void *parameter) {
leds[ledAddress(i)] = CRGB::Blue; leds[ledAddress(i)] = CRGB::Blue;
FastLED.show(); FastLED.show();
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
#else #else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
#endif #endif
@ -1817,7 +1896,7 @@ void showLed(void *parameter) {
for (uint8_t i=0; i<=100; i++) { for (uint8_t i=0; i<=100; i++) {
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
#else #else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
#endif #endif
@ -1831,7 +1910,7 @@ void showLed(void *parameter) {
leds[ledAddress(i)-1] = CRGB::Black; leds[ledAddress(i)-1] = CRGB::Black;
FastLED.show(); FastLED.show();
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
#else #else
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) { if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || !buttons[3].currentState) {
#endif #endif
@ -1862,7 +1941,7 @@ void showLed(void *parameter) {
FastLED.show(); FastLED.show();
for (uint8_t i=0; i<=50; i++) { for (uint8_t i=0; i<=50; i++) {
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || playProperties.playMode != NO_PLAYLIST || !buttons[3].currentState) {
if (hlastVolume != currentVolume || lastLedBrightness != ledBrightness || showLedError || showLedOk || showVoltageWarning || showLedVoltage || playProperties.playMode != NO_PLAYLIST || !buttons[3].currentState) {
#else #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[3].currentState) {
#endif #endif
@ -1901,7 +1980,7 @@ void showLed(void *parameter) {
default: // If playlist is active (doesn't matter which type) default: // If playlist is active (doesn't matter which type)
if (!playProperties.playlistFinished) { if (!playProperties.playlistFinished) {
#ifdef MEASURE_BATTERY_VOLTAGE #ifdef MEASURE_BATTERY_VOLTAGE
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || showVoltageWarning || !buttons[3].currentState) {
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || showVoltageWarning || showLedVoltage || !buttons[3].currentState) {
#else #else
if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || !buttons[3].currentState) { if (playProperties.pausePlay != lastPlayState || lockControls != lastLockState || notificationShown || ledBusyShown || volumeChangeShown || !buttons[3].currentState) {
#endif #endif
@ -2112,6 +2191,10 @@ void trackQueueDispatcher(const char *_itemToPlay, const uint32_t _lastPlayPos,
playProperties.saveLastPlayPosition = false; playProperties.saveLastPlayPosition = false;
playProperties.playUntilTrackNumber = 0; playProperties.playUntilTrackNumber = 0;
#ifdef PLAY_LAST_RFID_AFTER_REBOOT
storeLastRfidPlayed(currentRfidTagId);
#endif
switch(playProperties.playMode) { switch(playProperties.playMode) {
case SINGLE_TRACK: { case SINGLE_TRACK: {
loggerNl((char *) FPSTR(modeSingleTrack), LOGLEVEL_NOTICE); loggerNl((char *) FPSTR(modeSingleTrack), LOGLEVEL_NOTICE);
@ -2823,6 +2906,14 @@ String templateProcessor(const String& templ) {
return String(prefsSettings.getUInt("maxVolumeSp", 0)); return String(prefsSettings.getUInt("maxVolumeSp", 0));
} else if (templ == "MAX_VOLUME_HEADPHONE") { } else if (templ == "MAX_VOLUME_HEADPHONE") {
return String(prefsSettings.getUInt("maxVolumeHp", 0)); return String(prefsSettings.getUInt("maxVolumeHp", 0));
} else if (templ == "WARNING_LOW_VOLTAGE") {
return String(prefsSettings.getFloat("wLowVoltage", warningLowVoltage));
} else if (templ == "VOLTAGE_INDICATOR_LOW") {
return String(prefsSettings.getFloat("vIndicatorLow", voltageIndicatorLow));
} else if (templ == "VOLTAGE_INDICATOR_HIGH") {
return String(prefsSettings.getFloat("vIndicatorHigh", voltageIndicatorHigh));
} else if (templ == "VOLTAGE_CHECK_INTERVAL") {
return String(prefsSettings.getUInt("vCheckIntv", voltageCheckInterval));
} else if (templ == "MQTT_SERVER") { } else if (templ == "MQTT_SERVER") {
return prefsSettings.getString("mqttServer", "-1"); return prefsSettings.getString("mqttServer", "-1");
} else if (templ == "MQTT_ENABLE") { } else if (templ == "MQTT_ENABLE") {
@ -2875,6 +2966,10 @@ bool processJsonRequest(char *_serialJson) {
uint8_t iBright = doc["general"]["iBright"].as<uint8_t>(); uint8_t iBright = doc["general"]["iBright"].as<uint8_t>();
uint8_t nBright = doc["general"]["nBright"].as<uint8_t>(); uint8_t nBright = doc["general"]["nBright"].as<uint8_t>();
uint8_t iTime = doc["general"]["iTime"].as<uint8_t>(); uint8_t iTime = doc["general"]["iTime"].as<uint8_t>();
float vWarning = doc["general"]["vWarning"].as<float>();
float vIndLow = doc["general"]["vIndLow"].as<float>();
float vIndHi = doc["general"]["vIndHi"].as<float>();
uint8_t vInt = doc["general"]["vInt"].as<uint8_t>();
prefsSettings.putUInt("initVolume", iVol); prefsSettings.putUInt("initVolume", iVol);
prefsSettings.putUInt("maxVolumeSp", mVolSpeaker); prefsSettings.putUInt("maxVolumeSp", mVolSpeaker);
@ -2882,6 +2977,10 @@ bool processJsonRequest(char *_serialJson) {
prefsSettings.putUChar("iLedBrightness", iBright); prefsSettings.putUChar("iLedBrightness", iBright);
prefsSettings.putUChar("nLedBrightness", nBright); prefsSettings.putUChar("nLedBrightness", nBright);
prefsSettings.putUInt("mInactiviyT", iTime); prefsSettings.putUInt("mInactiviyT", iTime);
prefsSettings.putFloat("wLowVoltage", vWarning);
prefsSettings.putFloat("vIndicatorLow", vIndLow);
prefsSettings.putFloat("vIndicatorHigh", vIndHi);
prefsSettings.putUInt("vCheckIntv", vInt);
// Check if settings were written successfully // Check if settings were written successfully
if (prefsSettings.getUInt("initVolume", 0) != iVol || if (prefsSettings.getUInt("initVolume", 0) != iVol ||
@ -2889,7 +2988,11 @@ bool processJsonRequest(char *_serialJson) {
prefsSettings.getUInt("maxVolumeHp", 0) != mVolHeadphone | prefsSettings.getUInt("maxVolumeHp", 0) != mVolHeadphone |
prefsSettings.getUChar("iLedBrightness", 0) != iBright || prefsSettings.getUChar("iLedBrightness", 0) != iBright ||
prefsSettings.getUChar("nLedBrightness", 0) != nBright || prefsSettings.getUChar("nLedBrightness", 0) != nBright ||
prefsSettings.getUInt("mInactiviyT", 0) != iTime) {
prefsSettings.getUInt("mInactiviyT", 0) != iTime ||
prefsSettings.getFloat("wLowVoltage", 999.99) != vWarning ||
prefsSettings.getFloat("vIndicatorLow", 999.99) != vIndLow ||
prefsSettings.getFloat("vIndicatorHigh", 999.99) != vIndHi ||
prefsSettings.getUInt("vCheckIntv", 17777) != vInt) {
return false; return false;
} }
@ -3504,6 +3607,45 @@ void setup() {
loggerNl(logBuf, LOGLEVEL_INFO); loggerNl(logBuf, LOGLEVEL_INFO);
} }
#ifdef MEASURE_BATTERY_VOLTAGE
// Get voltages from NVS for Neopixel
float vLowIndicator = prefsSettings.getFloat("vIndicatorLow", 999.99);
if (vLowIndicator <= 999) {
voltageIndicatorLow = vLowIndicator;
snprintf(logBuf, serialLoglength, "%s: %.2f V", (char *) FPSTR(voltageIndicatorLowFromNVS), vLowIndicator);
loggerNl(logBuf, LOGLEVEL_INFO);
} else { // preseed if not set
prefsSettings.putFloat("vIndicatorLow", voltageIndicatorLow);
}
float vHighIndicator = prefsSettings.getFloat("vIndicatorHigh", 999.99);
if (vHighIndicator <= 999) {
voltageIndicatorHigh = vHighIndicator;
snprintf(logBuf, serialLoglength, "%s: %.2f V", (char *) FPSTR(voltageIndicatorHighFromNVS), vHighIndicator);
loggerNl(logBuf, LOGLEVEL_INFO);
} else {
prefsSettings.putFloat("vIndicatorHigh", voltageIndicatorHigh);
}
float vLowWarning = prefsSettings.getFloat("wLowVoltage", 999.99);
if (vLowWarning <= 999) {
warningLowVoltage = vLowWarning;
snprintf(logBuf, serialLoglength, "%s: %.2f V", (char *) FPSTR(warningLowVoltageFromNVS), vLowWarning);
loggerNl(logBuf, LOGLEVEL_INFO);
} else {
prefsSettings.putFloat("wLowVoltage", warningLowVoltage);
}
uint32_t vInterval = prefsSettings.getUInt("vCheckIntv", 17777);
if (vInterval != 17777) {
voltageCheckInterval = vInterval;
snprintf(logBuf, serialLoglength, "%s: %u Minuten", (char *) FPSTR(voltageCheckIntervalFromNVS), vInterval);
loggerNl(logBuf, LOGLEVEL_INFO);
} else {
prefsSettings.putUInt("vCheckIntv", voltageCheckInterval);
}
#endif
// Create 1000Hz-HW-Timer (currently only used for buttons) // Create 1000Hz-HW-Timer (currently only used for buttons)
timerSemaphore = xSemaphoreCreateBinary(); timerSemaphore = xSemaphoreCreateBinary();
timer = timerBegin(0, 240, true); // Prescaler: CPU-clock in MHz timer = timerBegin(0, 240, true); // Prescaler: CPU-clock in MHz
@ -3559,31 +3701,6 @@ void setup() {
lastTimeActiveTimestamp = millis(); // initial set after boot lastTimeActiveTimestamp = millis(); // initial set after boot
/*if (wifiManager() == WL_CONNECTED) {
// attach AsyncWebSocket for Mgmt-Interface
ws.onEvent(onWebsocketEvent);
wServer.addHandler(&ws);
// attach AsyncEventSource
wServer.addHandler(&events);
wServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/html", mgtWebsite, templateProcessor);
});
wServer.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", backupRecoveryWebsite);
}, handleUpload);
wServer.on("/restart", HTTP_GET, [] (AsyncWebServerRequest *request) {
request->send_P(200, "text/html", restartWebsite);
Serial.flush();
ESP.restart();
});
wServer.onNotFound(notFound);
wServer.begin();
}*/
bootComplete = true; bootComplete = true;
Serial.print(F("Free heap: ")); Serial.print(F("Free heap: "));
@ -3622,6 +3739,9 @@ void loop() {
lastTimeActiveTimestamp = millis(); // Re-adjust timer while client is connected to avoid ESP falling asleep lastTimeActiveTimestamp = millis(); // Re-adjust timer while client is connected to avoid ESP falling asleep
} }
#endif #endif
#ifdef PLAY_LAST_RFID_AFTER_REBOOT
recoverLastRfidPlayed();
#endif
} }

22
src/websiteMgmt.h

@ -180,6 +180,22 @@ static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\
<label for=\"inactivityTime\">Deep-Sleep nach Inaktivität (Minuten)</label>\ <label for=\"inactivityTime\">Deep-Sleep nach Inaktivität (Minuten)</label>\
<input type=\"number\" min=\"1\" max=\"1440\" class=\"form-control\" id=\"inactivityTime\" name=\"inactivityTime\" value=\"%MAX_INACTIVITY%\" required>\ <input type=\"number\" min=\"1\" max=\"1440\" class=\"form-control\" id=\"inactivityTime\" name=\"inactivityTime\" value=\"%MAX_INACTIVITY%\" required>\
</div>\ </div>\
<div class=\"form-group col-md-6\">\
<label for=\"warningLowVoltage\">(Optional) Spannungsgrenze (Batterie), ab der Warnung auf Neopixel angezeigt wird (z.B. 3.4)</label>\
<input type=\"text\" class=\"form-control\" id=\"warningLowVoltage\" name=\"warningLowVoltage\" value=\"%WARNING_LOW_VOLTAGE%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageIndicatorLow\">(Optional) Unterer Akkuspannungslevel (Batterie) für Neopixel-Anzeige (z.B. 3.1)</label>\
<input type=\"text\" class=\"form-control\" id=\"voltageIndicatorLow\" name=\"voltageIndicatorLow\" value=\"%VOLTAGE_INDICATOR_LOW%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageIndicatorHigh\">(Optional) Oberer Akkuspannungslevel (Batterie) für Neopixel-Anzeige (z.B. 4.2)</label>\
<input type=\"text\" class=\"form-control\" id=\"voltageIndicatorHigh\" name=\"voltageIndicatorHigh\" value=\"%VOLTAGE_INDICATOR_HIGH%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageCheckInterval\">(Optional) Häufigkeit der Spannungsmessung (Batterie) in Minuten</label>\
<input type=\"number\" min=\"1\" max=\"180\" class=\"form-control\" id=\"voltageCheckInterval\" name=\"voltageCheckInterval\" value=\"%VOLTAGE_CHECK_INTERVAL%\" required>\
</div>\
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\
<button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\
</form>\ </form>\
@ -271,7 +287,11 @@ static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\
mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\ mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\
iBright: document.getElementById('initBrightness').value,\ iBright: document.getElementById('initBrightness').value,\
nBright: document.getElementById('nightBrightness').value,\ nBright: document.getElementById('nightBrightness').value,\
iTime: document.getElementById('inactivityTime').value\
iTime: document.getElementById('inactivityTime').value,\
vWarning: document.getElementById('warningLowVoltage').value,\
vIndLow: document.getElementById('voltageIndicatorLow').value,\
vIndHi: document.getElementById('voltageIndicatorHigh').value,\
vInt: document.getElementById('voltageCheckInterval').value\
}\ }\
};\ };\
var myJSON = JSON.stringify(myObj);\ var myJSON = JSON.stringify(myObj);\

22
src/websiteMgmt_EN.h

@ -180,6 +180,22 @@ static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\
<label for=\"inactivityTime\">Deepsleep after inactivity (minutes)</label>\ <label for=\"inactivityTime\">Deepsleep after inactivity (minutes)</label>\
<input type=\"number\" min=\"1\" max=\"1440\" class=\"form-control\" id=\"inactivityTime\" name=\"inactivityTime\" value=\"%MAX_INACTIVITY%\" required>\ <input type=\"number\" min=\"1\" max=\"1440\" class=\"form-control\" id=\"inactivityTime\" name=\"inactivityTime\" value=\"%MAX_INACTIVITY%\" required>\
</div>\ </div>\
<div class=\"form-group col-md-6\">\
<label for=\"warningLowVoltage\">(Optional) Neopixel-warning will indicated below this battery-voltage (e.g. 3.4)</label>\
<input type=\"text\" class=\"form-control\" id=\"warningLowVoltage\" name=\"warningLowVoltage\" value=\"%WARNING_LOW_VOLTAGE%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageIndicatorLow\">(Optional) Lower voltage (battery) for Neopixel-visualisation (z.B. 3.1)</label>\
<input type=\"text\" class=\"form-control\" id=\"voltageIndicatorLow\" name=\"voltageIndicatorLow\" value=\"%VOLTAGE_INDICATOR_LOW%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageIndicatorHigh\">(Optional) Upper voltage (battery) for Neopixel-visualisation (z.B. 4.2)</label>\
<input type=\"text\" class=\"form-control\" id=\"voltageIndicatorHigh\" name=\"voltageIndicatorHigh\" value=\"%VOLTAGE_INDICATOR_HIGH%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required>\
</div>\
<div class=\"form-group col-md-6\">\
<label for=\"voltageCheckInterval\">(Optional) Interval of battery-measurement (minutes)</label>\
<input type=\"number\" min=\"1\" max=\"180\" class=\"form-control\" id=\"voltageCheckInterval\" name=\"voltageCheckInterval\" value=\"%VOLTAGE_CHECK_INTERVAL%\" required>\
</div>\
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\
<button type=\"submit\" class=\"btn btn-primary\">Submit</button>\ <button type=\"submit\" class=\"btn btn-primary\">Submit</button>\
</form>\ </form>\
@ -271,7 +287,11 @@ static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\
mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\ mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\
iBright: document.getElementById('initBrightness').value,\ iBright: document.getElementById('initBrightness').value,\
nBright: document.getElementById('nightBrightness').value,\ nBright: document.getElementById('nightBrightness').value,\
iTime: document.getElementById('inactivityTime').value\
iTime: document.getElementById('inactivityTime').value,\
vWarning: document.getElementById('warningLowVoltage').value,\
vIndLow: document.getElementById('voltageIndicatorLow').value,\
vIndHi: document.getElementById('voltageIndicatorHigh').value,\
vInt: document.getElementById('voltageCheckInterval').value\
}\ }\
};\ };\
var myJSON = JSON.stringify(myObj);\ var myJSON = JSON.stringify(myObj);\

Loading…
Cancel
Save