-
1.gitignore
-
54Hardware-Plaforms/Wemos Lolin32/README.md
-
BINPCBs/Wemos Lolin32/Gerber/gerber.zip
-
BINPCBs/Wemos Lolin32/KiCad/Kicad-files.zip
-
BINPCBs/Wemos Lolin32/Pictures/3d-Model downside.jpg
-
BINPCBs/Wemos Lolin32/Pictures/3d-Model upside.jpg
-
BINPCBs/Wemos Lolin32/Pictures/Tonuino-Lolin32-Schematics.pdf
-
54PCBs/Wemos Lolin32/README.md
-
40README.md
-
380html/website.html
-
263html/websiteMgmt.h
-
BINpictures/Mgmt-GUI1.jpg
-
BINpictures/Mgmt-GUI2.jpg
-
BINpictures/Mgmt-GUI3.jpg
-
BINpictures/Mgmt-GUI4.jpg
-
BINpictures/Mgmt-GUI5.jpg
-
BINpictures/Mgmt-GUI6.jpg
-
BINpictures/Mgmt-GUI_connection_broken.jpg
-
BINpictures/Mgmt_GUI_action_ok.jpg
-
6platformio.ini
-
6processHtml.py
-
373src/main.cpp
-
153src/settings.h
-
380src/websiteMgmt.h
@ -0,0 +1,54 @@ |
|||
# Tonuino-PCB based on Wemos' Lolin32 |
|||
|
|||
## Introduction |
|||
After I've been asked many times to provide a PCB, I finally did so :-) It makes use of Wemos' Lolin32 which is the predecessor of Lolin D32. D32's advantage over Lolin32 is especially, that a voltage-divider for measuring battery's voltage is already integrated (fixed-wired to GPIO 35). However, as I wasn't aware of that when buying Lolin32 and because of now, that multiple Lolin32 are here on my desk, my reasonable intention was to use them. So things would have been a bit easier with D32 but in the end it works the same way with Lolin32. |
|||
|
|||
## Features |
|||
* Fits Wemos Lolin32 (not Lolin D32, Lolin D32 pro or Lolin 32 lite!) |
|||
* Outer diameter: 56 x 93mm |
|||
* JST-PH 2.0-connectors for buttons, rotary encoder, Neopixel, RFID and battery (not 2.54mm pitch!) |
|||
* 2.54mm-connectors for MAX98354a and uSD-card-reader |
|||
* Mosfet-circuit that switches off MAX98357a, Neopixel, headphone-pcb and uSD-card-reader automatically when deepsleep is active |
|||
* All peripherals are solely driven at 3.3V! Keep this especially in mind when choosing uSD-reader. If in doubts use one without voltage-regulator (link below). |
|||
* If [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) is used, MAX98357a is automatically muted when there's a headphone plugged in and vice versa. |
|||
* If `HEADPHONE_ADJUST_ENABLE` is enabled and a headphone is plugged in, an alternative maximum volume is activated. I added this feature because [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) makes use of an amp that (probably) "allows" children to damage ears. This maximum volume can be set and re-adjusted via webgui. |
|||
|
|||
## Prerequisites |
|||
* If no [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) is connected, make sure `HEADPHONE_ADJUST_ENABLE` is not active. |
|||
* I used 390/130 kOhms-resistors as voltage-divider. However, make sure to use a multimeter to determine their exact values in order to achieve a better battery-measurement. They can be configured in `settings.h` as `rdiv1` und `rdiv2`. Hint: for Lolin D32's battery-measurement 100k+100k were used. However, I decided to change the ratio from 50/50% to 25/75% to have a "better" signal. 100/100 might be work as well; didn't test it. |
|||
|
|||
## Things to mention |
|||
* RFID: In order to avoid buying a 6pin-JST-PH-connector I used 2x3pin. This is because I already had ten of them (see link below). Accidently, on my PCB-layout, I switched the direction of one of these two connectors. However, it's just an visual issue. |
|||
* In contrast to Lolin D32, Lolin32 doesn't feature an integrated voltage-divider. That's why on the lower left there's a JST-PH2.0-connector to connect the LiPo-battery. Make sure to connect + to the left und GND to the right. From there you need to solder two short wires (5cm or so) onto the pcb with a JST-PH2.0-connector attached on the other side. This one needs to be plugged into Lolin32. Please note: Lolin's JST-PH2.0-connector needs (+) left side and GND right side. Don't be confused if black/red-colouring of the JST-wires used seems "weird" (black => (+); red => GND). |
|||
* Better don't solder Lolin32 directly to the PCB. I recommend to make use of female connectors instead (link below). |
|||
|
|||
## Hardware-setup |
|||
The heart of my project is an ESP32 on a [Wemos Lolin32 development-board](https://www.ebay.de/itm/4MB-Flash-WEMOS-Lolin32-V1-0-0-WIFI-Bluetooth-Card-Based-ESP-32-ESP-WROOM-32/162716855489). Make sure to install the drivers for the USB/Serial-chip (CP2102 e.g.). |
|||
* [MAX98357A (like Adafruit's)](https://de.aliexpress.com/item/32999952454.html) |
|||
* [uSD-card-reader 3.3V only](https://www.ebay.de/itm/Micro-SPI-Kartenleser-Card-Reader-2GB-SD-8GB-SDHC-Card-3-3V-ESP8266-Arduino-NEU/333796577968) |
|||
* [RFID-reader](https://www.amazon.de/AZDelivery-Reader-Arduino-Raspberry-gratis/dp/B074S8MRQ7) |
|||
* [RFID-tags](https://www.amazon.de/AZDelivery-Keycard-56MHz-Schlüsselkarte-Karte/dp/B07TVJPTM7) |
|||
* [Neopixel-ring](https://de.aliexpress.com/item/32673883645.html) |
|||
* [Rotary Encoder](https://de.aliexpress.com/item/33041814942.html) |
|||
* [Buttons](https://de.aliexpress.com/item/32896285438.html) |
|||
* [Speaker](https://www.visaton.de/de/produkte/chassiszubehoer/breitband-systeme/fr-7-4-ohm) |
|||
* uSD-card: doesn't have to be a super-fast one; uC is limiting the throughput. Tested 32GB without any problems. |
|||
* [JSP PH-2.0-connectors](https://de.aliexpress.com/item/32968344273.html) |
|||
* [Female connector](https://de.aliexpress.com/item/32724478308.html) |
|||
* [(optional) IDC-connector female 6pin for headphone-pcb](https://de.aliexpress.com/item/33029492417.html) |
|||
* [(optional) IDC-connector male 6pin for headphone-pcb](https://de.aliexpress.com/item/1005001400147026.html) |
|||
|
|||
## Parts |
|||
* 1x IRF530NPbF (N-channel MOSFET) |
|||
* 1x NDP6020P (P-channel MOSFET) |
|||
* 1x 1k resistor |
|||
* 1x 10k resistor |
|||
* 2x 100k resistor |
|||
* 1x 130k resistor (can be replaced by 100k) |
|||
* 1x 390k resistor (can be replaced by 100k) |
|||
|
|||
## Where to order? |
|||
I ordered my PCBs at [jlcpcb](https://jlcpcb.com/). You have to order at least 5 pcs, which is only at 2$ + shipping. It took two weeks to arrive. If you want to have a look at the PCBs first (without having KiCad installed), visit [Gerberlook](https://www.gerblook.org/) and upload `gerber.zip` from the Gerberfiles-folder. |
|||
|
|||
## Do I need to install KiCad? |
|||
Unless you don't want to change anything: no! All you need to provide are the gerberfiles (`gerber.zip`) to your manufactur (e.g. [jlcpcb](https://jlcpcb.com/)). However, all Kicad-files used are provided as well. |
After Width: 1438 | Height: 799 | Size: 53 KiB |
After Width: 1438 | Height: 799 | Size: 65 KiB |
@ -0,0 +1,54 @@ |
|||
# Tonuino-PCB based on Wemos' Lolin32 |
|||
|
|||
## Introduction |
|||
After I've been asked many times to provide a PCB, I finally did so :-) It makes use of Wemos' Lolin32 which is the predecessor of Lolin D32. D32's advantage over Lolin32 is especially, that a voltage-divider for measuring battery's voltage is already integrated (fixed-wired to GPIO 35). However, as I wasn't aware of that when buying Lolin32 and because of now, that multiple Lolin32 are here on my desk, my reasonable intention was to use them. So things would have been a bit easier with D32 but in the end it works the same way with Lolin32. |
|||
|
|||
## Features |
|||
* Fits Wemos Lolin32 (not Lolin D32, Lolin D32 pro or Lolin 32 lite!) |
|||
* Outer diameter: 56 x 93mm |
|||
* JST-PH 2.0-connectors for buttons, rotary encoder, Neopixel, RFID and battery (not 2.54mm pitch!) |
|||
* 2.54mm-connectors for MAX98354a and uSD-card-reader |
|||
* Mosfet-circuit that switches off MAX98357a, Neopixel, headphone-pcb and uSD-card-reader automatically when deepsleep is active |
|||
* All peripherals are solely driven at 3.3V! Keep this especially in mind when choosing uSD-reader. If in doubts use one without voltage-regulator (link below). |
|||
* If [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) is used, MAX98357a is automatically muted when there's a headphone plugged in and vice versa. |
|||
* If `HEADPHONE_ADJUST_ENABLE` is enabled and a headphone is plugged in, an alternative maximum volume is activated. I added this feature because [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) makes use of an amp that (probably) "allows" children to damage ears. This maximum volume can be set and re-adjusted via webgui. |
|||
|
|||
## Prerequisites |
|||
* If no [headphone-pcb](https://github.com/biologist79/Tonuino-ESP32-I2S/tree/master/PCBs/Headphone%20with%20PCM5102a%20and%20TMD1308) is connected, make sure `HEADPHONE_ADJUST_ENABLE` is not active. |
|||
* I used 390/130 kOhms-resistors as voltage-divider. However, make sure to use a multimeter to determine their exact values in order to achieve a better battery-measurement. They can be configured in `settings.h` as `rdiv1` und `rdiv2`. Hint: for Lolin D32's battery-measurement 100k+100k were used. However, I decided to change the ratio from 50/50% to 25/75% to have a "better" signal. 100/100 might be work as well; didn't test it. |
|||
|
|||
## Things to mention |
|||
* RFID: In order to avoid buying a 6pin-JST-PH-connector I used 2x3pin. This is because I already had ten of them (see link below). Accidently, on my PCB-layout, I switched the direction of one of these two connectors. However, it's just an visual issue. |
|||
* In contrast to Lolin D32, Lolin32 doesn't feature an integrated voltage-divider. That's why on the lower left there's a JST-PH2.0-connector to connect the LiPo-battery. Make sure to connect + to the left und GND to the right. From there you need to solder two short wires (5cm or so) onto the pcb with a JST-PH2.0-connector attached on the other side. This one needs to be plugged into Lolin32. Please note: Lolin's JST-PH2.0-connector needs (+) left side and GND right side. Don't be confused if black/red-colouring of the JST-wires used seems "weird" (black => (+); red => GND). |
|||
* Better don't solder Lolin32 directly to the PCB. I recommend to make use of female connectors instead (link below). |
|||
|
|||
## Hardware-setup |
|||
The heart of my project is an ESP32 on a [Wemos Lolin32 development-board](https://www.ebay.de/itm/4MB-Flash-WEMOS-Lolin32-V1-0-0-WIFI-Bluetooth-Card-Based-ESP-32-ESP-WROOM-32/162716855489). Make sure to install the drivers for the USB/Serial-chip (CP2102 e.g.). |
|||
* [MAX98357A (like Adafruit's)](https://de.aliexpress.com/item/32999952454.html) |
|||
* [uSD-card-reader 3.3V only](https://www.ebay.de/itm/Micro-SPI-Kartenleser-Card-Reader-2GB-SD-8GB-SDHC-Card-3-3V-ESP8266-Arduino-NEU/333796577968) |
|||
* [RFID-reader](https://www.amazon.de/AZDelivery-Reader-Arduino-Raspberry-gratis/dp/B074S8MRQ7) |
|||
* [RFID-tags](https://www.amazon.de/AZDelivery-Keycard-56MHz-Schlüsselkarte-Karte/dp/B07TVJPTM7) |
|||
* [Neopixel-ring](https://de.aliexpress.com/item/32673883645.html) |
|||
* [Rotary Encoder](https://de.aliexpress.com/item/33041814942.html) |
|||
* [Buttons](https://de.aliexpress.com/item/32896285438.html) |
|||
* [Speaker](https://www.visaton.de/de/produkte/chassiszubehoer/breitband-systeme/fr-7-4-ohm) |
|||
* uSD-card: doesn't have to be a super-fast one; uC is limiting the throughput. Tested 32GB without any problems. |
|||
* [JSP PH-2.0-connectors](https://de.aliexpress.com/item/32968344273.html) |
|||
* [Female connector](https://de.aliexpress.com/item/32724478308.html) |
|||
* [(optional) IDC-connector female 6pin for headphone-pcb](https://de.aliexpress.com/item/33029492417.html) |
|||
* [(optional) IDC-connector male 6pin for headphone-pcb](https://de.aliexpress.com/item/1005001400147026.html) |
|||
|
|||
## Parts |
|||
* 1x IRF530NPbF (N-channel MOSFET) |
|||
* 1x NDP6020P (P-channel MOSFET) |
|||
* 1x 1k resistor |
|||
* 1x 10k resistor |
|||
* 2x 100k resistor |
|||
* 1x 130k resistor (can be replaced by 100k) |
|||
* 1x 390k resistor (can be replaced by 100k) |
|||
|
|||
## Where to order? |
|||
I ordered my PCBs at [jlcpcb](https://jlcpcb.com/). You have to order at least 5 pcs, which is only at 2$ + shipping. It took two weeks to arrive. If you want to have a look at the PCBs first (without having KiCad installed), visit [Gerberlook](https://www.gerblook.org/) and upload `gerber.zip` from the Gerberfiles-folder. |
|||
|
|||
## Do I need to install KiCad? |
|||
Unless you don't want to change anything: no! All you need to provide are the gerberfiles (`gerber.zip`) to your manufactur (e.g. [jlcpcb](https://jlcpcb.com/)). However, all Kicad-files used are provided as well. |
@ -1,263 +0,0 @@ |
|||
static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\ |
|||
<html lang=\"de\">\ |
|||
<head>\ |
|||
<title>ESPuino-Konfiguration</title>\ |
|||
<meta charset=\"utf-8\">\ |
|||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\ |
|||
<link rel=\"stylesheet\" href=\"https://ts-cs.de/css/bootstrap.min.css\">\ |
|||
<script src=\"https://ts-cs.de/js/jquery.min.js\"></script>\ |
|||
<script src=\"https://ts-cs.de/js/popper.min.js\"></script>\ |
|||
<script src=\"https://ts-cs.de/js/bootstrap.min.js\"></script>\ |
|||
</head>\ |
|||
<body>\ |
|||
<nav class=\"navbar navbar-expand-sm bg-primary navbar-dark\">\ |
|||
<button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#navbarSupportedContent\" aria-controls=\"navbarSupportedContent\" aria-expanded=\"false\" aria-label=\"Toggle navigation\">\ |
|||
<span class=\"navbar-toggler-icon\"></span>\ |
|||
</button>\ |
|||
<a class=\"navbar-brand\">\ |
|||
<img src=\"./tonuino_logo.png\" width=\"30\" height=\"30\" class=\"d-inline-block align-top\" alt=\"\" />\ |
|||
Tonuino\ |
|||
</a>\ |
|||
<div class=\"collapse navbar-collapse\" id=\"collapsibleNavbar\">\ |
|||
<ul class=\"navbar-nav mr-auto\">\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#wifiConfig\">WLAN</a>\ |
|||
</li>\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#rfidMusicTags\">RFID-Zuweisungen</a>\ |
|||
</li>\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#rfidModTags\">RFID-Modifikationen</a>\ |
|||
</li>\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#mqttConfig\">MQTT</a>\ |
|||
</li>\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#ftpConfig\">FTP</a>\ |
|||
</li>\ |
|||
<li class=\"nav-item\">\ |
|||
<a class=\"nav-link\" href=\"#generalConfig\">Allgemein</a>\ |
|||
</li>\ |
|||
</ul>\ |
|||
</div>\ |
|||
</nav>\ |
|||
<br />\ |
|||
<div class=\"container\" id=\"wifiConfig\">\ |
|||
<h2>WLAN-Konfiguration</h2>\ |
|||
<form action=\"#wifiConfig\" method=\"GET\">\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"SSID\">WLAN-Name (SSID):</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"SSID\" placeholder=\"SSID\" name=\"SSID\" required>\ |
|||
<div class=\"invalid-feedback\">\ |
|||
Bitte SSID des WLANs eintragen.\ |
|||
</div>\ |
|||
<label for=\"pwd\">Passwort:</label>\ |
|||
<input type=\"password\" class=\"form-control\" id=\"pwd\" placeholder=\"Passwort\" name=\"pwd\" required>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onclick=\"wifiConfig()\">Absenden</button>\ |
|||
</form>\ |
|||
</div>\ |
|||
<div class=\"container my-5\" id=\"rfidMusicTags\">\ |
|||
<h2>RFID-Zuweisungen</h2>\ |
|||
<form action=\"#rfidMusicTags\" method=\"GET\">\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"rfidIdMusic\">RFID-Chip-Nummer</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"rfidIdMusic\" maxlength=\"12\" pattern=\"[0-9]{12}\" placeholder=\"012345678912\" name=\"rfidIdMusic\" required>\ |
|||
<label for=\"fileOrUrl\">Datei, Verzeichnis oder URL (URL nur für Webradio)</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"fileOrUrl\" maxlength=\"255\" placeholder=\"z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3\" name=\"fileOrUrl\" required>\ |
|||
<label for=\"playMode\">Abspielmodus</label>\ |
|||
<select class=\"form-control\" id=\"playMode\" name=\"playMode\">\ |
|||
<option value=\"1\">Einzelner Titel</option>\ |
|||
<option value=\"2\">Einzelner Titel (Endlosschleife)</option>\ |
|||
<option value=\"3\">Hörbuch</option>\ |
|||
<option value=\"4\">Hörbuch (Endlosschleife)</option>\ |
|||
<option value=\"5\">Alle Titel eines Verzeichnis (sortiert)</option>\ |
|||
<option value=\"6\">Alle Titel eines Verzeichnis (zufällig)</option>\ |
|||
<option value=\"7\">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option>\ |
|||
<option value=\"8\">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>\ |
|||
<option value=\"9\">Webradio</option>\ |
|||
</select>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onclick=\"rfidAssign()\">Absenden</button>\ |
|||
</form>\ |
|||
</div>\ |
|||
<div class=\"container my-5\" id=\"rfidModTags\">\ |
|||
<h2>RFID-Modifkationen</h2>\ |
|||
<form class=\"needs-validation\" action=\"#rfidModTags\" method=\"GET\" novalidate>\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"rfidIdMod\">RFID-Chip-Nummer</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"rfidIdMod\" maxlength=\"12\" pattern=\"[0-9]{12}\" placeholder=\"012345678912\" name=\"rfidIdMod\" required>\ |
|||
<div class=\"invalid-feedback\">\ |
|||
Bitte eine 12-stellige Zahl eingeben.\ |
|||
</div>\ |
|||
<label for=\"modId\">Abspielmodus</label>\ |
|||
<select class=\"form-control\" id=\"modId\" name=\"modId\">\ |
|||
<option value=\"100\">Tastensperre</option>\ |
|||
<option value=\"101\">Schlafen nach 15 Minuten</option>\ |
|||
<option value=\"102\">Schlafen nach 30 Minuten</option>\ |
|||
<option value=\"103\">Schlafen nach 1 Stunde</option>\ |
|||
<option value=\"104\">Schlafen nach 2 Stunden</option>\ |
|||
<option value=\"105\">Schlafen nach Ende des Titels</option>\ |
|||
<option value=\"106\">Schlafen nach Ende der Playlist</option>\ |
|||
<option value=\"110\">Wiederhole Playlist (endlos)</option>\ |
|||
<option value=\"111\">Wiederhole Titel (endlos)</option>\ |
|||
<option value=\"112\">Dimme LEDs (Nachtmodus)</option>\ |
|||
</select>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onclick=\"rfidMods()\">Absenden</button>\ |
|||
</form>\ |
|||
</div>\ |
|||
<div class=\"container my-5\" id=\"mqttConfig\">\ |
|||
<h2>MQTT-Konfiguration</h2>\ |
|||
<form class=\"needs-validation\" action=\"#mqttConfig\" method=\"GET\" novalidate>\ |
|||
<div class=\"form-check col-md-6\">\ |
|||
<input class=\"form-check-input\" type=\"checkbox\" value=\"1\" id=\"mqttEnable\" name=\"mqttEnable\" %MQTT_ENABLE%>\ |
|||
<label class=\"form-check-label\" for=\"mqttEnable\">\ |
|||
MQTT aktivieren\ |
|||
</label>\ |
|||
</div>\ |
|||
<div class=\"form-group my-2 col-md-6\">\ |
|||
<label for=\"mqttServer\">MQTT-Server (IP-Adresse)</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"mqttServer\" pattern=\"^((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$\" minlength=\"7\" maxlength=\"15\" placeholder=\"z.B. 192.168.2.89\" name=\"mqttServer\" value=\"%MQTT_SERVER%\">\ |
|||
<div class=\"invalid-feedback\">\ |
|||
Bitte eine gültige IPv4-Adresse eingeben, z.B. 192.168.2.89.\ |
|||
</div>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onclick=\"mqttSettings()\">Absenden</button>\ |
|||
</form>\ |
|||
</div>\ |
|||
<div class=\"container\" id=\"ftpConfig\">\ |
|||
<h2>FTP-Konfiguration</h2>\ |
|||
<form action=\"#ftpConfig\" method=\"GET\">\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"ftpUser\">FTP-Benutzername:</label>\ |
|||
<input type=\"text\" class=\"form-control\" id=\"ftpUser\" maxlength=\"32\" placeholder=\"Benutzername\" name=\"ftpUser\" value=\"%FTP_USER%\" required>\ |
|||
<label for=\"pwd\">Passwort:</label>\ |
|||
<input type=\"password\" class=\"form-control\" id=\"ftpPwd\" maxlength=\"32\" placeholder=\"Passwort\" name=\"ftpPwd\" value=\"%FTP_PWD%\" required>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onClick=\"ftpSettings()\">Absenden</button>\ |
|||
</form>\ |
|||
</div>\ |
|||
<div class=\"container my-5\" id=\"generalConfig\">\ |
|||
<h2>Allgemeine Konfiguration</h2>\ |
|||
<form action=\"#generalConfig\" method=\"GET\">\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"initialVolume\">Lautstärke nach dem Einschalten</label>\ |
|||
<input type=\"number\" min=\"1\" max=\"21\" class=\"form-control\" id=\"initialVolume\" name=\"initialVolume\" value=\"%INIT_VOLUME%\" required>\ |
|||
<label for=\"maxVolume\">Maximale Lautstärke</label>\ |
|||
<input type=\"number\" min=\"1\" max=\"21\" class=\"form-control\" id=\"maxVolume\" name=\"maxVolume\" value=\"%MAX_VOLUME%\" required>\ |
|||
</div>\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<label for=\"initBrightness\">Neopixel-Helligkeit nach dem Einschalten</label>\ |
|||
<input type=\"number\" min=\"0\" max=\"255\" class=\"form-control\" id=\"initBrightness\" name=\"initBrightness\" value=\"%INIT_LED_BRIGHTBESS%\" required>\ |
|||
<label for=\"nightBrightness\">Neopixel-Helligkeit im Nachtmodus</label>\ |
|||
<input type=\"number\" min=\"0\" max=\"255\" class=\"form-control\" id=\"nightBrightness\" name=\"nightBrightness\" value=\"%NIGHT_LED_BRIGHTBESS%\" required>\ |
|||
</div>\ |
|||
<div class=\"form-group col-md-6\">\ |
|||
<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>\ |
|||
</div>\ |
|||
<button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |
|||
<button type=\"submit\" class=\"btn btn-primary\" onClick=\"genSettings()\">Absenden</button>\ |
|||
</form>\ |
|||
<script>\ |
|||
(function() {\ |
|||
'use strict';\ |
|||
window.addEventListener('load', function() {\ |
|||
// Fetch all the forms we want to apply custom Bootstrap validation styles to\ |
|||
var forms = document.getElementsByClassName('needs-validation');\ |
|||
// Loop over them and prevent submission\ |
|||
var validation = Array.prototype.filter.call(forms, function(form) {\ |
|||
form.addEventListener('submit', function(event) {\ |
|||
if (form.checkValidity() === false) {\ |
|||
event.preventDefault();\ |
|||
event.stopPropagation();\ |
|||
}\ |
|||
form.classList.add('was-validated');\ |
|||
}, false);\ |
|||
});\ |
|||
}, false);\ |
|||
});\ |
|||
\ |
|||
let socket = new WebSocket(\"ws://%IPv4%:81/ws\");\ |
|||
\ |
|||
function genSettings() {\ |
|||
\ |
|||
var myObj = {\ |
|||
\"general\": {\ |
|||
iVol: document.getElementById('initialVolume').value,\ |
|||
mVol: document.getElementById('maxVolume').value,\ |
|||
iBright: document.getElementById('initBrightness').value,\ |
|||
nBright: document.getElementById('nightBrightness').value,\ |
|||
iTime: document.getElementById('inactivityTime').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
\ |
|||
function ftpSettings() {\ |
|||
var myObj = {\ |
|||
\"ftp\": {\ |
|||
ftpUser: document.getElementById('ftpUser').value,\ |
|||
ftpPwd: document.getElementById('ftpPwd').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
\ |
|||
function mqttSettings() {\ |
|||
var myObj = {\ |
|||
\"mqtt\": {\ |
|||
enable: document.getElementById('mqttEnable').value,\ |
|||
server: document.getElementById('mqttServer').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
\ |
|||
function rfidMods() {\ |
|||
var myObj = {\ |
|||
\"rfidMod\": {\ |
|||
rfidId: document.getElementById('rfidIdMod').value,\ |
|||
modId: document.getElementById('modId').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
\ |
|||
function rfidAssign() {\ |
|||
var myObj = {\ |
|||
\"rfidAssign\": {\ |
|||
rfidId: document.getElementById('rfidIdMusic').value,\ |
|||
fileOrUrl: document.getElementById('fileOrUrl').value,\ |
|||
playmode: document.getElementById('playMode').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
\ |
|||
function wifiConfig() {\ |
|||
var myObj = {\ |
|||
\"wifiConfig\": {\ |
|||
ssid: document.getElementById('SSID').value,\ |
|||
pwd: document.getElementById('pwd').value\ |
|||
}\ |
|||
};\ |
|||
var myJSON = JSON.stringify(myObj);\ |
|||
socket.send(myJSON);\ |
|||
}\ |
|||
</script>\ |
|||
</div>\ |
|||
</body>\ |
|||
</html>\ |
|||
"; |
Before Width: 1080 | Height: 1856 | Size: 336 KiB After Width: 1080 | Height: 1208 | Size: 197 KiB |
Before Width: 1080 | Height: 1223 | Size: 188 KiB After Width: 883 | Height: 1280 | Size: 190 KiB |
Before Width: 1080 | Height: 1644 | Size: 240 KiB After Width: 825 | Height: 1280 | Size: 132 KiB |
Before Width: 1080 | Height: 1471 | Size: 245 KiB After Width: 921 | Height: 1280 | Size: 132 KiB |
Before Width: 1080 | Height: 602 | Size: 81 KiB After Width: 851 | Height: 1280 | Size: 156 KiB |
After Width: 1080 | Height: 1857 | Size: 313 KiB |
Before Width: 1080 | Height: 1853 | Size: 242 KiB After Width: 1080 | Height: 1206 | Size: 236 KiB |
Before Width: 1080 | Height: 1843 | Size: 268 KiB After Width: 1032 | Height: 1280 | Size: 137 KiB |
@ -0,0 +1,153 @@ |
|||
#include "Arduino.h" |
|||
|
|||
//########################## MODULES ################################# |
|||
#define MQTT_ENABLE // Make sure to configure mqtt-server and (optionally) username+pwd |
|||
#define FTP_ENABLE // Enables FTP-server |
|||
#define NEOPIXEL_ENABLE // Don't forget configuration of NUM_LEDS if enabled |
|||
#define NEOPIXEL_REVERSE_ROTATION // Some Neopixels are adressed/soldered counter-clockwise. This can be configured here. |
|||
#define LANGUAGE 1 // 1 = deutsch; 2 = english |
|||
//#define HEADPHONE_ADJUST_ENABLE // Used to adjust (lower) volume for optional headphone-pcb (refer maxVolumeSpeaker / maxVolumeHeadphone) |
|||
#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 SINGLE_SPI_ENABLE // If only one SPI-instance should be used instead of two (not yet working!) |
|||
//#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 |
|||
|
|||
|
|||
|
|||
//################## GPIO-configuration ############################## |
|||
// uSD-card-reader (via SPI) |
|||
#define SPISD_CS 15 // GPIO for chip select (SD) |
|||
#ifndef SINGLE_SPI_ENABLE |
|||
#define SPISD_MOSI 13 // GPIO for master out slave in (SD) => not necessary for single-SPI |
|||
#define SPISD_MISO 16 // GPIO for master in slave ou (SD) => not necessary for single-SPI |
|||
#define SPISD_SCK 14 // GPIO for clock-signal (SD) => not necessary for single-SPI |
|||
#endif |
|||
|
|||
// 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 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) |
|||
|
|||
// I2S (DAC) |
|||
#define I2S_DOUT 25 // Digital out (I2S) |
|||
#define I2S_BCLK 27 // BCLK (I2S) |
|||
#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 is used to switch Tonuino on and off |
|||
|
|||
// Control-buttons |
|||
#define PAUSEPLAY_BUTTON 5 // GPIO to detect pause/play |
|||
#define NEXT_BUTTON 4 // GPIO to detect next |
|||
#define PREVIOUS_BUTTON 2 // GPIO to detect previous (Important: as of 19.11.2020 changed from 33 to 2) |
|||
|
|||
// (optional) Power-control |
|||
#define POWER 17 // GPIO used to drive transistor-circuit, that switches off peripheral devices while ESP32-deepsleep |
|||
|
|||
// (optional) Neopixel |
|||
#define LED_PIN 12 // GPIO for Neopixel-signaling |
|||
|
|||
// (optinal) Headphone-detection |
|||
#ifdef HEADPHONE_ADJUST_ENABLE |
|||
#define HP_DETECT 22 // GPIO that detects, if there's a plug in the headphone jack or not |
|||
#endif |
|||
|
|||
// (optional) Monitoring of battery-voltage via ADC |
|||
#ifdef MEASURE_BATTERY_VOLTAGE |
|||
#define VOLTAGE_READ_PIN 33 // GPIO used to monitor battery-voltage. Change to 35 if you're using Lolin D32 or Lolin D32 pro as it's hard-wired there! |
|||
#endif |
|||
|
|||
|
|||
|
|||
//#################### Various settings ############################## |
|||
// Loglevels available (don't change!) |
|||
#define LOGLEVEL_ERROR 1 // only errors |
|||
#define LOGLEVEL_NOTICE 2 // errors + important messages |
|||
#define LOGLEVEL_INFO 3 // infos + errors + important messages |
|||
#define LOGLEVEL_DEBUG 4 // almost everything |
|||
|
|||
// Serial-logging-configuration |
|||
const uint8_t serialDebug = LOGLEVEL_DEBUG; // Current loglevel for serial console |
|||
|
|||
// Buttons (better leave unchanged if in doubts :-)) |
|||
uint8_t buttonDebounceInterval = 50; // Interval in ms to software-debounce buttons |
|||
uint16_t intervalToLongPress = 700; // Interval in ms to distinguish between short and long press of previous/next-button |
|||
|
|||
// RFID |
|||
#define RFID_SCAN_INTERVAL 300 // Interval-time in ms (how often is RFID read?) |
|||
|
|||
// Automatic restart |
|||
#ifdef SHUTDOWN_IF_SD_BOOT_FAILS |
|||
uint32_t deepsleepTimeAfterBootFails = 20; // Automatic restart takes place if boot was not successful after this period (in seconds) |
|||
#endif |
|||
|
|||
// FTP |
|||
// Nothing to be configured here... |
|||
// Default user/password is esp32/esp32 but can be changed via webgui |
|||
|
|||
// Tonuino will create a WiFi if joing existing WiFi was not possible. Name can be configured here. |
|||
static const char accessPointNetworkSSID[] PROGMEM = "Tonuino"; // Access-point's SSID |
|||
|
|||
// Where to store the backup-file for NVS-records |
|||
#ifndef SD_NOT_MANDATORY_ENABLE |
|||
static const char backupFile[] PROGMEM = "/backup.txt"; // File is written every time a (new) RFID-assignment via GUI is done |
|||
#endif |
|||
|
|||
// (webgui) File Browser |
|||
uint8_t FS_DEPTH = 5; // Max. recursion-depth of file tree |
|||
const char *DIRECTORY_INDEX_FILE = "/files.json"; // Filename of files.json index file |
|||
|
|||
// (optinal) Neopixel |
|||
#ifdef NEOPIXEL_ENABLE |
|||
#define NUM_LEDS 24 // number of LEDs |
|||
#define CHIPSET WS2812B // type of Neopixel |
|||
#define COLOR_ORDER GRB |
|||
#endif |
|||
|
|||
// (optional) Default-voltages for battery-monitoring via Neopixel |
|||
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!) |
|||
|
|||
// (optinal) For measuring battery-voltage a voltage-divider is necessary. Their values need to be configured here. |
|||
#ifdef MEASURE_BATTERY_VOLTAGE |
|||
uint8_t rdiv1 = 129; // Rdiv1 of voltage-divider (kOhms) (measure exact value with multimeter!) |
|||
uint16_t rdiv2 = 389; // Rdiv2 of voltage-divider (kOhms) (measure exact value with multimeter!) => used to measure voltage via ADC! |
|||
#endif |
|||
|
|||
// (optinal) Headphone-detection (leave unchanged if in doubts...) |
|||
#ifdef HEADPHONE_ADJUST_ENABLE |
|||
uint16_t headphoneLastDetectionDebounce = 1000; // Debounce-interval in ms when plugging in headphone |
|||
#endif |
|||
|
|||
// (optional) Topics for MQTT |
|||
#ifdef MQTT_ENABLE |
|||
#define DEVICE_HOSTNAME "ESP32-Tonuino-Leonie" // Name that that is used for MQTT |
|||
static const char topicSleepCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/Sleep"; |
|||
static const char topicSleepState[] PROGMEM = "State/Tonuino-Leonie/Sleep"; |
|||
static const char topicTrackCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/Track"; |
|||
static const char topicTrackState[] PROGMEM = "State/Tonuino-Leonie/Track"; |
|||
static const char topicTrackControlCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/TrackControl"; |
|||
static const char topicLoudnessCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/Loudness"; |
|||
static const char topicLoudnessState[] PROGMEM = "State/Tonuino-Leonie/Loudness"; |
|||
static const char topicSleepTimerCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/SleepTimer"; |
|||
static const char topicSleepTimerState[] PROGMEM = "State/Tonuino-Leonie/SleepTimer"; |
|||
static const char topicState[] PROGMEM = "State/Tonuino-Leonie/State"; |
|||
static const char topicCurrentIPv4IP[] PROGMEM = "State/Tonuino-Leonie/IPv4"; |
|||
static const char topicLockControlsCmnd[] PROGMEM ="Cmnd/Tonuino-Leonie/LockControls"; |
|||
static const char topicLockControlsState[] PROGMEM ="State/Tonuino-Leonie/LockControls"; |
|||
static const char topicPlaymodeState[] PROGMEM = "State/Tonuino-Leonie/Playmode"; |
|||
static const char topicRepeatModeCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/RepeatMode"; |
|||
static const char topicRepeatModeState[] PROGMEM = "State/Tonuino-Leonie/RepeatMode"; |
|||
static const char topicLedBrightnessCmnd[] PROGMEM = "Cmnd/Tonuino-Leonie/LedBrightness"; |
|||
static const char topicLedBrightnessState[] PROGMEM = "State/Tonuino-Leonie/LedBrightness"; |
|||
static const char topicBatteryVoltage[] PROGMEM = "State/Tonuino-Leonie/Voltage"; |
|||
#endif |