12 changed files with 1544 additions and 1352 deletions
			
			
		- 
					0html/accesspoint.html
- 
					0html/accesspoint_EN.html
- 
					727html/management.html
- 
					0html/management_EN.html
- 
					639html/website.html
- 
					133processHtml.py
- 
					6src/HTMLaccesspoint.h
- 
					2src/HTMLaccesspoint_EN.h
- 
					728src/HTMLmanagement.h
- 
					2src/HTMLmanagement_EN.h
- 
					19src/main.cpp
- 
					640src/websiteMgmt.h
| @ -0,0 +1,727 @@ | |||||
|  | <!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/tonuino/css/bootstrap.min.css"> | ||||
|  |     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css"/> | ||||
|  |     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/> | ||||
|  |     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css"/> | ||||
|  |     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/css/bootstrap-slider.min.css" /> | ||||
|  |     <script src="https://ts-cs.de/tonuino/js/jquery.min.js"></script> | ||||
|  |     <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script> | ||||
|  |     <script src="https://ts-cs.de/tonuino/js/popper.min.js"></script> | ||||
|  |     <script src="https://ts-cs.de/tonuino/js/bootstrap.min.js"></script> | ||||
|  |     <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> | ||||
|  |     <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script> | ||||
|  |     <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/bootstrap-slider.min.js"></script> | ||||
|  |     <style type="text/css"> | ||||
|  |         .filetree { | ||||
|  |             border: 1px solid black; | ||||
|  |             height: 200px; | ||||
|  |             margin: 0em 0em 1em 0em; | ||||
|  |             overflow-y: scroll; | ||||
|  |         } | ||||
|  |         .slider.slider-horizontal { | ||||
|  |             width: 60%; | ||||
|  |             margin-left: 1em; | ||||
|  |             margin-right: 1em; | ||||
|  | 
 | ||||
|  |         } | ||||
|  |         .slider-handle{ | ||||
|  |             height: 30px; | ||||
|  |             width: 30px; | ||||
|  |             top: -5px; | ||||
|  |         } | ||||
|  |       | ||||
|  |         legend.scheduler-border { | ||||
|  |             width:inherit; /* Or auto */ | ||||
|  |             padding:0 10px; /* To give a bit of padding on the left and right */ | ||||
|  |             border-bottom:none; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .icon-pos{ | ||||
|  |             top: 0.3em; | ||||
|  |             position: relative; | ||||
|  |          } | ||||
|  |         .reboot{ | ||||
|  |             color:white; | ||||
|  |         } | ||||
|  |         .reboot:hover{ | ||||
|  |             color: orange; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .fa-sync:hover { | ||||
|  |             color: #666666; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .clickForRefresh { | ||||
|  |             text-align: center; | ||||
|  |             color: gray; | ||||
|  |             cursor: pointer; | ||||
|  |             margin-top: 5em; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .clickForRefresh:hover { | ||||
|  |             color: darkgray; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .filetree-container { | ||||
|  |             position: relative; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .indexing-progress { | ||||
|  |             width: 100%; | ||||
|  |             height: 100%; | ||||
|  |             position: absolute; | ||||
|  |             top: 0; | ||||
|  |             left: 0; | ||||
|  |             opacity: 0.7; | ||||
|  |             display: none; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .refreshAction{ | ||||
|  |             text-align: right; | ||||
|  |             font-size: 0.8em; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .refreshAction:hover{ | ||||
|  |             cursor: pointer; | ||||
|  |             color: darkgray; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         .overlay { | ||||
|  |             z-index: 9; | ||||
|  |             opacity: 0.8; | ||||
|  |             background: #1a1919; | ||||
|  |             height: 200px; | ||||
|  |             display: none; | ||||
|  |             width: 100%; | ||||
|  |         } | ||||
|  |     </style> | ||||
|  | </head> | ||||
|  | <body> | ||||
|  | <nav class="navbar navbar-expand-sm bg-primary navbar-dark"> | ||||
|  |     <div class="col-md-12"> | ||||
|  |     <a class="float-left navbar-brand"> | ||||
|  |         <img src="https://raw.githubusercontent.com/biologist79/Tonuino-ESP32-I2S/master/html/tonuino_logo.png" | ||||
|  |              width="30" height="30" class="d-inline-block align-top" alt=""/> | ||||
|  |         Tonuino | ||||
|  |     </a> | ||||
|  | 
 | ||||
|  |     <a class="reboot float-right nav-link" href="/restart"><i class="fas fa-power-off"></i> Neustart</a> | ||||
|  |     </div> | ||||
|  | </nav> | ||||
|  | <br/> | ||||
|  |     <nav> | ||||
|  |         <div class="container nav nav-tabs" id="nav-tab" role="tablist"> | ||||
|  |             <a class="nav-item nav-link active" id="nav-rfid-tab" data-toggle="tab" href="#nav-rfid" role="tab" aria-controls="nav-rfid" aria-selected="true"><i class="fas fa-dot-circle"></i> RFID</a> | ||||
|  |             <a class="nav-item nav-link" id="nav-wifi-tab" data-toggle="tab" href="#nav-wifi" role="tab" aria-controls="nav-wifi" aria-selected="false"><i class="fas fa-wifi"></i><span class=".d-sm-none .d-md-block"> WLAN</span></a> | ||||
|  |             <a class="nav-item nav-link" id="nav-mqtt-tab" data-toggle="tab" href="#nav-mqtt" role="tab" aria-controls="nav-mqtt" aria-selected="false"><i class="fas fa-network-wired"></i> MQTT</a> | ||||
|  |             <a class="nav-item nav-link" id="nav-ftp-tab" data-toggle="tab" href="#nav-ftp" role="tab" aria-controls="nav-ftp" aria-selected="false"><i class="fas fa-folder"></i> FTP</a> | ||||
|  |             <a class="nav-item nav-link" id="nav-general-tab" data-toggle="tab" href="#nav-general" role="tab" aria-controls="nav-general" aria-selected="false"><i class="fas fa-sliders-h"></i> Allgemein</a> | ||||
|  |             <a class="nav-item nav-link" id="nav-tools-tab" data-toggle="tab" href="#nav-tools" role="tab" aria-controls="nav-tools" aria-selected="false"><i class="fas fa-wrench"></i> Tools</a> | ||||
|  |         </div> | ||||
|  |     </nav> | ||||
|  | <br> | ||||
|  | <div class="tab-content" id="nav-tabContent"> | ||||
|  |     <div class="tab-pane fade" id="nav-wifi" role="tabpanel" aria-labelledby="nav-wifi-tab"> | ||||
|  |         <div class="container" id="wifiConfig"> | ||||
|  |             <form action="#wifiConfig" method="POST" onsubmit="wifiConfig('wifiConfig'); return false"> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <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> | ||||
|  |                     <label for="hostname">Tonuino-Name (Hostname):</label> | ||||
|  |                     <input type="text" class="form-control" id="hostname" placeholder="tonuino" name="hostname" | ||||
|  |                            value="%HOSTNAME%" pattern="^[^-\.]{2,32}" required> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  |     <div class="tab-pane fade show active" id="nav-rfid" role="tabpanel" aria-labelledby="nav-rfid-tab"> | ||||
|  |         <div class="container" id="rfidMusicTags"> | ||||
|  |             <fieldset> | ||||
|  |                 <legend>RFID-Zuweisungen</legend> | ||||
|  |             <form action="#rfidMusicTags" method="POST" onsubmit="rfidAssign('rfidMusicTags'); return false"> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <label for="rfidIdMusic">RFID-Chip-Nummer (12-stellig)</label> | ||||
|  |                     <input type="text" class="form-control" id="rfidIdMusic" maxlength="12" pattern="[0-9]{12}" | ||||
|  |                            placeholder="%RFID_TAG_ID%" name="rfidIdMusic" required> | ||||
|  |                     <label for="fileOrUrl">Datei, Verzeichnis oder URL (^ und # als Zeichen nicht erlaubt)</label> | ||||
|  |                     <input type="text" class="form-control" id="fileOrUrl" maxlength="255" placeholder="z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3" pattern="^[^\^#]+$" name="fileOrUrl" required> | ||||
|  |                     <div class="filetree-container"> | ||||
|  |                         <div id="filebrowser"> | ||||
|  |                             <div class="filetree demo" id="filetree"></div> | ||||
|  |                             <div class="refreshAction"> | ||||
|  |                                 <span id="refreshAction" data-toggle="tooltip" data-placement="top" title="Datei Liste aktualisieren."><i class="fas fa-sync fa-1x"></i> Dateiliste aktualisieren</span> | ||||
|  |                             </div> | ||||
|  |                         </div> | ||||
|  |                         <div id="indexing-progress" class="indexing-progress overlay"> | ||||
|  |                             <div style="text-align: center; color:white; margin-top:2em;"> | ||||
|  |                                 <div><i class="fas fa-sync fa-spin fa-2x"></i> <br><br>  Der Prozess kann mehrere Minuten dauern...</div> | ||||
|  |                                 <div id="currentProcessedFile"></div> | ||||
|  |                             </div> | ||||
|  |                         </div> | ||||
|  |                     </div> | ||||
|  |                     <label for="playMode">Abspielmodus</label> | ||||
|  |                     <select class="form-control" id="playMode" name="playMode"> | ||||
|  |                         <option class="option-file" value="1">Einzelner Titel</option> | ||||
|  |                         <option class="option-file" value="2">Einzelner Titel (Endlosschleife)</option> | ||||
|  |                         <option class="option-file-and-folder" value="3">Hörbuch</option> | ||||
|  |                         <option class="option-file-and-folder" value="4">Hörbuch (Endlosschleife)</option> | ||||
|  |                         <option class="option-folder" value="5">Alle Titel eines Verzeichnis (sortiert)</option> | ||||
|  |                         <option class="option-folder" value="6">Alle Titel eines Verzeichnis (zufällig)</option> | ||||
|  |                         <option class="option-folder" value="7">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option> | ||||
|  |                         <option class="option-folder" value="9">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option> | ||||
|  |                         <option class="option-stream" value="8">Webradio</option> | ||||
|  |                     </select> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |             </fieldset> | ||||
|  |         </div> | ||||
|  | 
 | ||||
|  |         <br> | ||||
|  |         <br> | ||||
|  |         <div class="container" id="rfidModTags"> | ||||
|  |             <fieldset> | ||||
|  |                 <legend>RFID-Modifkationen</legend> | ||||
|  |             <form class="needs-validation" action="#rfidModTags" method="POST" onsubmit="rfidMods('rfidModTags'); return false"> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <label for="rfidIdMod">RFID-Chip-Nummer (12-stellig)</label> | ||||
|  |                     <input type="text" class="form-control" id="rfidIdMod" maxlength="12" pattern="[0-9]{12}" | ||||
|  |                            placeholder="%RFID_TAG_ID%" name="rfidIdMod" required> | ||||
|  |                     <div class="invalid-feedback"> | ||||
|  |                         Bitte eine 12-stellige Zahl eingeben. | ||||
|  |                     </div> | ||||
|  |                     <label for="modId">Konfiguraiton</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="107">Schlafen nach fünf Titeln</option> | ||||
|  |                         <option value="110">Wiederhole Playlist (endlos)</option> | ||||
|  |                         <option value="111">Wiederhole Titel (endlos)</option> | ||||
|  |                         <option value="112">Dimme LEDs (Nachtmodus)</option> | ||||
|  |                         <option value="130">Aktiviere/deaktive WLAN</option> | ||||
|  |                     </select> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |             </fieldset> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  |     <div class="tab-pane fade" id="nav-mqtt" role="tabpanel" aria-labelledby="nav-mqtt-tab"> | ||||
|  |         <div class="container" id="mqttConfig"> | ||||
|  | 
 | ||||
|  |             <form class="needs-validation" action="#mqttConfig" method="POST" | ||||
|  |                   onsubmit="mqttSettings('mqttConfig'); return false"> | ||||
|  |                 <div class="form-check col-md-12"> | ||||
|  |                     <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-12"> | ||||
|  |                     <label for="mqttServer">MQTT-Server</label> | ||||
|  |                     <input type="text" class="form-control" id="mqttServer" minlength="7" maxlength="%MQTT_SERVER_LENGTH%" | ||||
|  |                            placeholder="z.B. 192.168.2.89" name="mqttServer" value="%MQTT_SERVER%"> | ||||
|  |                     <label for="mqttUser">MQTT-Benutzername (optional):</label> | ||||
|  |                     <input type="text" class="form-control" id="mqttUser" maxlength="%MQTT_USER_LENGTH%" | ||||
|  |                            placeholder="Benutzername" name="mqttUser" value="%MQTT_USER%"> | ||||
|  |                     <label for="mqttPwd">Passwort (optional):</label> | ||||
|  |                     <input type="password" class="form-control" id="mqttPwd" maxlength="%MQTT_PWD_LENGTH%" | ||||
|  |                            placeholder="Passwort" name="mqttPwd" value="%MQTT_PWD%"> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  |     <div class="tab-pane fade" id="nav-ftp" role="tabpanel" aria-labelledby="nav-ftp-tab"> | ||||
|  |         <div class="container" id="ftpConfig"> | ||||
|  | 
 | ||||
|  |             <form action="#ftpConfig" method="POST" onsubmit="ftpSettings('ftpConfig'); return false"> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <label for="ftpUser">FTP-Benutzername:</label> | ||||
|  |                     <input type="text" class="form-control" id="ftpUser" maxlength="%FTP_USER_LENGTH%" | ||||
|  |                            placeholder="Benutzername" name="ftpUser" value="%FTP_USER%" required> | ||||
|  |                     <label for="pwd">Passwort:</label> | ||||
|  |                     <input type="password" class="form-control" id="ftpPwd" maxlength="%FTP_PWD_LENGTH%" placeholder="Passwort" | ||||
|  |                            name="ftpPwd" value="%FTP_PWD%" required> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  | 
 | ||||
|  |     <div class="tab-pane fade" id="nav-general" role="tabpanel" aria-labelledby="nav-general-tab"> | ||||
|  |         <div class="container" id="generalConfig"> | ||||
|  | 
 | ||||
|  |             <form action="#generalConfig" method="POST" onsubmit="genSettings('generalConfig'); return false"> | ||||
|  |                     <div class="form-group col-md-12"> | ||||
|  |                     <fieldset> | ||||
|  |                             <legend class="w-auto">Lautstärke</legend> | ||||
|  |                     <label for="initialVolume">Nach dem Einschalten</label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                     <i class="fas fa-volume-down fa-2x .icon-pos"></i> <input data-provide="slider" type="number" data-slider-min="1" data-slider-max="21" min="1" max="21" class="form-control" id="initialVolume" name="initialVolume" | ||||
|  |                         data-slider-value="%INIT_VOLUME%"  value="%INIT_VOLUME%" required>  <i class="fas fa-volume-up fa-2x .icon-pos"></i></div> | ||||
|  |                         <br> | ||||
|  |                     <label for="maxVolumeSpeaker">Maximal Lautsprecher</label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                      <i class="fas fa-volume-down fa-2x .icon-pos"></i>   <input data-provide="slider" type="number" data-slider-min="1" data-slider-max="21" min="1" max="21" class="form-control" id="maxVolumeSpeaker" name="maxVolumeSpeaker" | ||||
|  |                         data-slider-value="%MAX_VOLUME_SPEAKER%"  value="%MAX_VOLUME_SPEAKER%" required>  <i class="fas fa-volume-up fa-2x .icon-pos"></i> | ||||
|  |                         </div> | ||||
|  |                         <br> | ||||
|  |                     <label for="maxVolumeHeadphone">Maximal Kopfhörer</label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                     <i class="fas fa-volume-down fa-2x .icon-pos"></i> <input data-provide="slider" type="number" data-slider-min="1" data-slider-max="21" min="1" max="21" class="form-control" id="maxVolumeHeadphone" name="maxVolumeHeadphone" | ||||
|  |                          data-slider-value="%MAX_VOLUME_HEADPHONE%" value="%MAX_VOLUME_HEADPHONE%" required>  <i class="fas fa-volume-up fa-2x .icon-pos"></i> | ||||
|  |                         </div> | ||||
|  |                 </fieldset> | ||||
|  |                 </div> | ||||
|  | <br> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <fieldset > | ||||
|  |                         <legend  class="w-auto">Neopixel (Helligkeit)</legend> | ||||
|  |                     <label for="initBrightness">Nach dem Einschalten:</label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                             <i class="far fa-sun fa-2x .icon-pos"></i> | ||||
|  |                         <input data-provide="slider" type="number" data-slider-min="0" data-slider-max="255" min="0" max="255" class="form-control" id="initBrightness" name="initBrightness" | ||||
|  |                                data-slider-value="%INIT_LED_BRIGHTNESS%"  value="%INIT_LED_BRIGHTNESS%" required><i class="fas fa-sun fa-2x .icon-pos"></i> | ||||
|  |                         </div> | ||||
|  | 
 | ||||
|  |                     <label for="nightBrightness">Im Nachtmodus</label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                         <i class="far fa-sun fa-2x .icon-pos"></i><input data-provide="slider" type="number" data-slider-min="0" data-slider-max="255" min="0" max="255" class="form-control" id="nightBrightness" name="nightBrightness" data-slider-value="%NIGHT_LED_BRIGHTNESS%" value="%NIGHT_LED_BRIGHTNESS%" required><i class="fas fa-sun fa-2x .icon-pos"></i> | ||||
|  |                         </div> | ||||
|  |                     </fieldset> | ||||
|  |                 </div> | ||||
|  | <br> | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <fieldset> | ||||
|  |                         <legend>Deep Sleep</legend> | ||||
|  | 
 | ||||
|  |                         <label for="inactivityTime">Inaktivität nach (in Minuten)</label> | ||||
|  |                         <div class="text-center"><i class="fas fa-hourglass-start fa-2x .icon-pos"></i> <input type="number" data-provide="slider" data-slider-min="0" data-slider-max="30" min="1" max="120" class="form-control" id="inactivityTime" name="inactivityTime" | ||||
|  |                          data-slider-value="%MAX_INACTIVITY%"  value="%MAX_INACTIVITY%" required><i class="fas fa-hourglass-end fa-2x .icon-pos"></i></div> | ||||
|  |                     </fieldset> | ||||
|  |                 </div> | ||||
|  | <br> | ||||
|  | 
 | ||||
|  |                 <div class="form-group col-md-12"> | ||||
|  |                     <fieldset> | ||||
|  |                         <legend>Batterie</legend> | ||||
|  |                     <div>Status über Neopixel anzeigen</div> | ||||
|  |                         <br> | ||||
|  |                     <label for="warningLowVoltage">Spannungsgrenze für Status Anzeige. | ||||
|  |                     </label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                         <i class="fas fa-battery-quarter fa-2x .icon-pos"></i> <input  data-provide="slider"  data-slider-step="0.1" data-slider-min="3.0" data-slider-max="5.0"  min="3.0" max="5.0" type="text" class="form-control" id="warningLowVoltage" name="warningLowVoltage" | ||||
|  |                         data-slider-value="%WARNING_LOW_VOLTAGE%" value="%WARNING_LOW_VOLTAGE%" pattern="^\d{1,2}(\.\d{1,3})?" required> <i class="fas fa-battery-three-quarters fa-2x .icon-pos" fa-2x .icon-pos></i> | ||||
|  |                         </div> | ||||
|  | <br> | ||||
|  |                     <label for="voltageIndicatorLow">Unterer Akkuspannungslevel | ||||
|  |                         </label> | ||||
|  |                         <div class="text-center"> | ||||
|  |                         <i class="fas fa-battery-quarter fa-2x .icon-pos"></i> <input data-provide="slider" min="2.0" data-slider-step="0.1"  data-slider-min="2.0" data-slider-max="5.0" max="5.0"type="text" class="form-control" id="voltageIndicatorLow" name="voltageIndicatorLow" | ||||
|  |                           data-slider-value="%VOLTAGE_INDICATOR_LOW%"  value="%VOLTAGE_INDICATOR_LOW%" pattern="^\d{1,2}(\.\d{1,3})?" required> <i class="fas fa-battery-three-quarters fa-2x .icon-pos" fa-2x .icon-pos></i> | ||||
|  |                         </div> | ||||
|  |                         <br> | ||||
|  |                         <label for="voltageIndicatorHigh">Oberer Akkuspannungslevel</label> | ||||
|  | 
 | ||||
|  |                             <div class="text-center"> | ||||
|  |                                 <i class="fas fa-battery-quarter fa-2x .icon-pos"></i><input data-provide="slider" data-slider-step="0.1"  data-slider-min="2.0" data-slider-max="5.0" min="2.0" max="5.0" type="text" class="form-control" id="voltageIndicatorHigh" name="voltageIndicatorHigh" | ||||
|  |                            data-slider-value="%VOLTAGE_INDICATOR_HIGH%"  value="%VOLTAGE_INDICATOR_HIGH%" pattern="^\d{1,2}(\.\d{1,3})?" required> <i class="fas fa-battery-three-quarters fa-2x .icon-pos" fa-2x .icon-pos></i> | ||||
|  |                         </div> | ||||
|  | 
 | ||||
|  |                         <br> | ||||
|  |                     <label for="voltageCheckInterval"> Interval der Messung (in Minuten)</label> | ||||
|  |                         <div class="text-center"><i class="fas fa-hourglass-start fa-2x .icon-pos"></i> | ||||
|  |                             <input data-provide="slider" data-slider-min="1" data-slider-max="60" type="number" min="1" max="60" class="form-control" id="voltageCheckInterval" | ||||
|  |                                    data-slider-value="%VOLTAGE_CHECK_INTERVAL%"  name="voltageCheckInterval" value="%VOLTAGE_CHECK_INTERVAL%" required><i class="fas fa-hourglass-end fa-2x .icon-pos"></i> | ||||
|  |                     </div> | ||||
|  | 
 | ||||
|  |                     </fieldset> | ||||
|  |                 </div> | ||||
|  | <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="reset" class="btn btn-secondary">Reset</button> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  |     <div class="tab-pane fade" id="nav-tools" role="tabpanel" aria-labelledby="nav-tools-tab"> | ||||
|  |         <div class="container my-5" id="importNvs"> | ||||
|  |             <h2>NVS-Importer</h2> | ||||
|  |             <form action="/upload" enctype="multipart/form-data" method="POST"> | ||||
|  |                 <div class="form-group"> | ||||
|  |                     <label for="nvsUpload">Hier kann eine Backup-Datei importiert werden.</label> | ||||
|  |                     <input type="file" class="form-control-file" id="nvsUpload" name="nvsUpload" accept=".txt"> | ||||
|  |                 </div> | ||||
|  |                 <br> | ||||
|  |                 <div class="text-center"> | ||||
|  |                 <button type="submit" class="btn btn-primary">Absenden</button> | ||||
|  |                 </div> | ||||
|  |             </form> | ||||
|  |         </div> | ||||
|  |     </div> | ||||
|  | </div> | ||||
|  | <script type="text/javascript"> | ||||
|  |     var DEBUG = false; | ||||
|  |     var lastIdclicked = ''; | ||||
|  |     var host = $(location).attr('hostname'); | ||||
|  | 
 | ||||
|  |     if (DEBUG) { | ||||
|  |         host = "192.168.178.114"; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     toastr.options = { | ||||
|  |         "closeButton": false, | ||||
|  |         "debug": false, | ||||
|  |         "newestOnTop": false, | ||||
|  |         "progressBar": false, | ||||
|  |         "positionClass": "toast-top-right", | ||||
|  |         "preventDuplicates": false, | ||||
|  |         "onclick": null, | ||||
|  |         "showDuration": "300", | ||||
|  |         "hideDuration": "1000", | ||||
|  |         "timeOut": "5000", | ||||
|  |         "extendedTimeOut": "1000", | ||||
|  |         "showEasing": "swing", | ||||
|  |         "hideEasing": "linear", | ||||
|  |         "showMethod": "fadeIn", | ||||
|  |         "hideMethod": "fadeOut" | ||||
|  |     }; | ||||
|  | 
 | ||||
|  |     function postRendering(event, data) { | ||||
|  |         Object.keys(data.instance._model.data).forEach(function (key, index) { | ||||
|  | 
 | ||||
|  |             var cur = data.instance.get_node(data.instance._model.data[key]); | ||||
|  |             var lastFolder = cur['id'].split('/').filter(function (el) { | ||||
|  |                 return el.trim().length > 0; | ||||
|  |             }).pop(); | ||||
|  |             if ((/\.(mp3|MP3|ogg|wav|WAV|OGG|wma|WMA|acc|ACC|flac|FLAC)$/i).test(lastFolder)) { | ||||
|  |                 data.instance.set_type(data.instance._model.data[key], 'audio'); | ||||
|  |             } else { | ||||
|  |                 if (data.instance._model.data[key]['type'] == "file") { | ||||
|  |                     data.instance.disable_node(data.instance._model.data[key]); | ||||
|  |                 } | ||||
|  |             } | ||||
|  |             data.instance.rename_node(data.instance._model.data[key], lastFolder); | ||||
|  |         }); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function renderFileTree() { | ||||
|  | 
 | ||||
|  |         var filesURI = "/files"; | ||||
|  |         if (DEBUG) { | ||||
|  |             filesURI = "http://" + host + "/files"; | ||||
|  |         } | ||||
|  |         $('#filetree').jstree({ | ||||
|  |             'core': { | ||||
|  |                 'check_callback': true, | ||||
|  |                 'data': { | ||||
|  |                     url: filesURI, | ||||
|  |                     error: function (XMLHttpRequest, textStatus, errorThrown) { | ||||
|  |                         $('#j1_loading').hide(); | ||||
|  |                         $("#refreshAction").hide(); | ||||
|  |                         $('#filetree').html("<div class='clickForRefresh' ><i class='fas fa-sync fa-1x'><span id='#clickForRefresh' > Dateien suchen.</span></div>"); | ||||
|  |                         $('#filetree').on("click", function () { | ||||
|  |                             refreshFileList(); | ||||
|  |                         }); | ||||
|  |                         toastr.error("Die Verzeichnis-Liste konnte nicht geladen werden."); | ||||
|  |                     } | ||||
|  |                 }, | ||||
|  | 
 | ||||
|  |             }, | ||||
|  |             'types': { | ||||
|  |                 'folder': { | ||||
|  |                     'icon': "fa fa-folder" | ||||
|  |                 }, | ||||
|  |                 'file': { | ||||
|  |                     'icon': "fa fa-file" | ||||
|  |                 }, | ||||
|  |                 'audio': { | ||||
|  |                     'icon': "fa fa-file-audio" | ||||
|  |                 }, | ||||
|  |                 'default': { | ||||
|  |                     'icon': "fa fa-folder" | ||||
|  |                 } | ||||
|  |             }, | ||||
|  |             'plugins': ["themes", "types"] | ||||
|  |         }).bind('loaded.jstree', function (event, data) { | ||||
|  |             postRendering(event, data); | ||||
|  |             if ((data.instance._model.data['#']['children'].length == 0)) { | ||||
|  |                 toastr.info("Der SD-Karten-Index muss erzeugt werden."); | ||||
|  |             } | ||||
|  |         }).bind('refresh.jstree', function (event, data) { | ||||
|  |             postRendering(event, data); | ||||
|  |         }); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     $('#filetree').on('select_node.jstree', function (e, data) { | ||||
|  |         $('input[name=fileOrUrl]').val(data.node.id); | ||||
|  | 
 | ||||
|  |         if (data.node.type == "folder") { | ||||
|  |             $('.option-folder').show(); | ||||
|  |             $('.option-file').hide(); | ||||
|  |             $('#playMode option').removeAttr('selected').filter('[value=3]').attr('selected', true); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         if (data.node.type == "audio") { | ||||
|  |             $('.option-file').show(); | ||||
|  |             $('.option-folder').hide(); | ||||
|  |             $('#playMode option').removeAttr('selected').filter('[value=1]').attr('selected', true); | ||||
|  |         } | ||||
|  |     }); | ||||
|  | 
 | ||||
|  |     $('#refreshAction').on("click", function () { | ||||
|  |         refreshFileList(); | ||||
|  |         $("#indexing-progress").show(); | ||||
|  |         $("#refreshAction").hide(); | ||||
|  |     }); | ||||
|  | 
 | ||||
|  |     $('#playMode').on("change", function () { | ||||
|  |         if (this.value == 8) { | ||||
|  |             $('#filebrowser').slideUp(); | ||||
|  |         } else { | ||||
|  |             $('#filebrowser').slideDown(); | ||||
|  |         } | ||||
|  |     }); | ||||
|  | 
 | ||||
|  |     function showFileIndexingState() { | ||||
|  |         $("#indexing-progress").show(); | ||||
|  |         $("#refreshAction").hide(); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function hideFileIndexingState() { | ||||
|  |         $("#indexing-progress").hide(); | ||||
|  |         $("#refreshAction").show(); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     var socket = undefined; | ||||
|  |     var tm; | ||||
|  | 
 | ||||
|  |     function connect() { | ||||
|  |         socket = new WebSocket("ws://" + host + "/ws"); | ||||
|  | 
 | ||||
|  |         socket.onopen = function () { | ||||
|  |             setInterval(ping, 15000); | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         socket.onclose = function (e) { | ||||
|  |             console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason); | ||||
|  |             socket = null; | ||||
|  |             setTimeout(function () { | ||||
|  |                 connect(); | ||||
|  |             }, 5000); | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         socket.onerror = function (err) { | ||||
|  |             console.error('Socket encountered error: ', err.message, 'Closing socket'); | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         socket.onmessage = function(event) { | ||||
|  |           console.log(event.data); | ||||
|  |           var socketMsg = JSON.parse(event.data); | ||||
|  |           if (socketMsg.rfidId != null) { | ||||
|  |               document.getElementById('rfidIdMod').value = socketMsg.rfidId; | ||||
|  |               document.getElementById('rfidIdMusic').value = socketMsg.rfidId; | ||||
|  |               toastr.info("RFID Tag mit "+ socketMsg.rfidId + " erkannt." ); | ||||
|  | 
 | ||||
|  |               $("#rfidIdMusic").effect("highlight", {color:"#abf5af"}, 3000); | ||||
|  |               $("#rfidIdMod").effect("highlight", {color:"#abf5af"}, 3000); | ||||
|  | 
 | ||||
|  |           } if ("status" in socketMsg) { | ||||
|  |               if (socketMsg.status == "ok") { | ||||
|  |                   toastr.success("Aktion erfolgreich ausgeführt." ); | ||||
|  |               } | ||||
|  |           } if ("pong" in socketMsg) { | ||||
|  |               if (socketMsg.pong == 'pong') { | ||||
|  |                   pong(); | ||||
|  |               } | ||||
|  |           } if ("refreshFileList" in socketMsg) { | ||||
|  |               hideFileIndexingState(); | ||||
|  |               toastr.info("Die Dateiliste wurde neu erzeugt!"); | ||||
|  |               $('#filetree').jstree(true).refresh(); | ||||
|  | 
 | ||||
|  |           } | ||||
|  |           if ("indexingState" in socketMsg) { | ||||
|  |               if(socketMsg.indexingState != null) { | ||||
|  |                   $("#currentProcessedFile").text(socketMsg.indexingState); | ||||
|  |                   console.log(socketMsg.indexingState); | ||||
|  |               } | ||||
|  |           } | ||||
|  |       }; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function ping() { | ||||
|  |         var myObj = { | ||||
|  |             "ping": { | ||||
|  |                 ping: 'ping' | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |         tm = setTimeout(function () { | ||||
|  |             toastr.warning('Die Verbindung zum Tonuino ist unterbrochen! Bitte Seite neu laden.'); | ||||
|  |         }, 5000); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function pong() { | ||||
|  |         clearTimeout(tm); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function refreshFileList(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "refreshFileList": true | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         $("#refreshAction").hide(); | ||||
|  |         socket.send(myJSON); | ||||
|  |         showFileIndexingState(); | ||||
|  |     }; | ||||
|  | 
 | ||||
|  |     function genSettings(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "general": { | ||||
|  |                 iVol: document.getElementById('initialVolume').value, | ||||
|  |                 mVolSpeaker: document.getElementById('maxVolumeSpeaker').value, | ||||
|  |                 mVolHeadphone: document.getElementById('maxVolumeHeadphone').value, | ||||
|  |                 iBright: document.getElementById('initBrightness').value, | ||||
|  |                 nBright: document.getElementById('nightBrightness').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); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function ftpSettings(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "ftp": { | ||||
|  |                 ftpUser: document.getElementById('ftpUser').value, | ||||
|  |                 ftpPwd: document.getElementById('ftpPwd').value | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function mqttSettings(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var val; | ||||
|  |         if (document.getElementById('mqttEnable').checked) { | ||||
|  |             val = document.getElementById('mqttEnable').value; | ||||
|  |         } else { | ||||
|  |             val = 0; | ||||
|  |         } | ||||
|  |         var myObj = { | ||||
|  |             "mqtt": { | ||||
|  |                 mqttEnable: val, | ||||
|  |                 mqttServer: document.getElementById('mqttServer').value, | ||||
|  |                 mqttUser: document.getElementById('mqttUser').value, | ||||
|  |                 mqttPwd: document.getElementById('mqttPwd').value | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function rfidMods(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "rfidMod": { | ||||
|  |                 rfidIdMod: document.getElementById('rfidIdMod').value, | ||||
|  |                 modId: document.getElementById('modId').value | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function removeTrSlash(str) { | ||||
|  |         if (str.substr(-1) === '/') { | ||||
|  |             return str.substr(0, str.length - 1); | ||||
|  |         } | ||||
|  |         return str; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function rfidAssign(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "rfidAssign": { | ||||
|  |                 rfidIdMusic: document.getElementById('rfidIdMusic').value, | ||||
|  |                 fileOrUrl: removeTrSlash(document.getElementById('fileOrUrl').value), | ||||
|  |                 playMode: document.getElementById('playMode').value | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     function wifiConfig(clickedId) { | ||||
|  |         lastIdclicked = clickedId; | ||||
|  |         var myObj = { | ||||
|  |             "wifiConfig": { | ||||
|  |                 ssid: document.getElementById('ssid').value, | ||||
|  |                 pwd: document.getElementById('pwd').value, | ||||
|  |                 hostname: document.getElementById('hostname').value | ||||
|  |             } | ||||
|  |         }; | ||||
|  |         var myJSON = JSON.stringify(myObj); | ||||
|  |         socket.send(myJSON); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     $(document).ready(function () { | ||||
|  |         connect(); | ||||
|  |         renderFileTree(); | ||||
|  | 
 | ||||
|  |         console.log(parseInt(document.getElementById('warningLowVoltage').value)); | ||||
|  |         $(function () { | ||||
|  |             $('[data-toggle="tooltip"]').tooltip(); | ||||
|  |         }); | ||||
|  | 
 | ||||
|  |     }); | ||||
|  | </script> | ||||
|  | </body> | ||||
|  | </html> | ||||
| @ -1,639 +0,0 @@ | |||||
| <!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/tonuino/css/bootstrap.min.css"> |  | ||||
|     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css"/> |  | ||||
|     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/> |  | ||||
|     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css"/> |  | ||||
|     <script src="https://ts-cs.de/tonuino/js/jquery.min.js"></script> |  | ||||
|     <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script> |  | ||||
|     <script src="https://ts-cs.de/tonuino/js/popper.min.js"></script> |  | ||||
|     <script src="https://ts-cs.de/tonuino/js/bootstrap.min.js"></script> |  | ||||
|     <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> |  | ||||
|     <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script> |  | ||||
|     <style type="text/css"> |  | ||||
|         .filetree { |  | ||||
|             border: 1px solid black; |  | ||||
|             height: 200px; |  | ||||
|             margin: 0em 0em 1em 0em; |  | ||||
|             overflow-y: scroll; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .fa-sync:hover { |  | ||||
|             color: #666666; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .clickForRefresh { |  | ||||
|             text-align: center; |  | ||||
|             color: gray; |  | ||||
|             cursor: pointer; |  | ||||
|             margin-top: 5em; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .clickForRefresh:hover { |  | ||||
|             color: darkgray; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .filetree-container { |  | ||||
|             position: relative; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .indexing-progress { |  | ||||
|             width: 100%; |  | ||||
|             height: 100%; |  | ||||
|             position: absolute; |  | ||||
|             top: 0; |  | ||||
|             left: 0; |  | ||||
|             opacity: 0.7; |  | ||||
|             display: none; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .refreshAction{ |  | ||||
|             text-align: right; |  | ||||
|             font-size: 0.8em; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .refreshAction:hover{ |  | ||||
|             cursor: pointer; |  | ||||
|             color: darkgray; |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         .overlay { |  | ||||
|             z-index: 9; |  | ||||
|             opacity: 0.8; |  | ||||
|             background: #1a1919; |  | ||||
|             height: 200px; |  | ||||
|             display: none; |  | ||||
|             width: 100%; |  | ||||
|         } |  | ||||
|     </style> |  | ||||
| </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="https://raw.githubusercontent.com/biologist79/Tonuino-ESP32-I2S/master/html/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> |  | ||||
|             <li class="nav-item"> |  | ||||
|                 <a class="nav-link" href="#importNvs">NVS-Importer</a> |  | ||||
|             </li> |  | ||||
|             <li class="nav-item"> |  | ||||
|                 <a class="nav-link" href="/restart" style="color: orange">Neustart Tonuino</a> |  | ||||
|             </li> |  | ||||
|         </ul> |  | ||||
|     </div> |  | ||||
| </nav> |  | ||||
| <br/> |  | ||||
| <div class="container" id="wifiConfig"> |  | ||||
|     <h2>WLAN-Konfiguration</h2> |  | ||||
|     <form action="#wifiConfig" method="POST" onsubmit="wifiConfig('wifiConfig'); return false"> |  | ||||
|         <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> |  | ||||
|             <label for="hostname">Tonuino-Name (Hostname):</label> |  | ||||
|             <input type="text" class="form-control" id="hostname" placeholder="tonuino" name="hostname" |  | ||||
|                    value="%HOSTNAME%" pattern="^[^-\.]{2,32}" required> |  | ||||
|         </div> |  | ||||
|         <button type="reset" class="btn btn-secondary">Reset</button> |  | ||||
|         <button type="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container my-5" id="rfidMusicTags"> |  | ||||
|     <h2>RFID-Zuweisungen</h2> |  | ||||
|     <form action="#rfidMusicTags" method="POST" onsubmit="rfidAssign('rfidMusicTags'); return false"> |  | ||||
|         <div class="form-group col-md-6"> |  | ||||
|             <label for="rfidIdMusic">RFID-Chip-Nummer (12-stellig)</label> |  | ||||
|             <input type="text" class="form-control" id="rfidIdMusic" maxlength="12" pattern="[0-9]{12}" |  | ||||
|                    placeholder="%RFID_TAG_ID%" name="rfidIdMusic" required> |  | ||||
|             <label for="fileOrUrl">Datei, Verzeichnis oder URL (^ und # als Zeichen nicht erlaubt)</label> |  | ||||
|             <input type="text" class="form-control" id="fileOrUrl" maxlength="255" placeholder="z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3" pattern="^[^\^#]+$" name="fileOrUrl" required> |  | ||||
|             <div class="filetree-container"> |  | ||||
|                 <div id="filebrowser"> |  | ||||
|                     <div class="filetree demo" id="filetree"></div> |  | ||||
|                     <div class="refreshAction"> |  | ||||
|                         <span id="refreshAction" data-toggle="tooltip" data-placement="top" title="Datei Liste aktualisieren."><i class="fas fa-sync fa-1x"></i> Dateiliste aktualisieren</span> |  | ||||
|                     </div> |  | ||||
|                 </div> |  | ||||
|                 <div id="indexing-progress" class="indexing-progress overlay"> |  | ||||
|                     <div style="text-align: center; color:white; margin-top:2em;"> |  | ||||
|                         <div><i class="fas fa-sync fa-spin fa-2x"></i> <br><br>  Der Prozess kann mehrere Minuten dauern...</div> |  | ||||
|                         <div id="currentProcessedFile"></div> |  | ||||
|                     </div> |  | ||||
|                 </div> |  | ||||
|             </div> |  | ||||
|             <label for="playMode">Abspielmodus</label> |  | ||||
|             <select class="form-control" id="playMode" name="playMode"> |  | ||||
|                 <option class="option-file" value="1">Einzelner Titel</option> |  | ||||
|                 <option class="option-file" value="2">Einzelner Titel (Endlosschleife)</option> |  | ||||
|                 <option class="option-file-and-folder" value="3">Hörbuch</option> |  | ||||
|                 <option class="option-file-and-folder" value="4">Hörbuch (Endlosschleife)</option> |  | ||||
|                 <option class="option-folder" value="5">Alle Titel eines Verzeichnis (sortiert)</option> |  | ||||
|                 <option class="option-folder" value="6">Alle Titel eines Verzeichnis (zufällig)</option> |  | ||||
|                 <option class="option-folder" value="7">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option> |  | ||||
|                 <option class="option-folder" value="9">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option> |  | ||||
|                 <option class="option-stream" value="8">Webradio</option> |  | ||||
|             </select> |  | ||||
|         </div> |  | ||||
|         <button type="reset" class="btn btn-secondary">Reset</button> |  | ||||
|         <button type="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container my-5" id="rfidModTags"> |  | ||||
|     <h2>RFID-Modifkationen</h2> |  | ||||
|     <form class="needs-validation" action="#rfidModTags" method="POST" onsubmit="rfidMods('rfidModTags'); return false"> |  | ||||
|         <div class="form-group col-md-6"> |  | ||||
|             <label for="rfidIdMod">RFID-Chip-Nummer (12-stellig)</label> |  | ||||
|             <input type="text" class="form-control" id="rfidIdMod" maxlength="12" pattern="[0-9]{12}" |  | ||||
|                    placeholder="%RFID_TAG_ID%" 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="107">Schlafen nach fünf Titeln</option> |  | ||||
|                 <option value="110">Wiederhole Playlist (endlos)</option> |  | ||||
|                 <option value="111">Wiederhole Titel (endlos)</option> |  | ||||
|                 <option value="112">Dimme LEDs (Nachtmodus)</option> |  | ||||
|                 <option value="130">Aktiviere/deaktive WLAN</option> |  | ||||
|             </select> |  | ||||
|         </div> |  | ||||
|         <button type="reset" class="btn btn-secondary">Reset</button> |  | ||||
|         <button type="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container my-5" id="mqttConfig"> |  | ||||
|     <h2>MQTT-Konfiguration</h2> |  | ||||
|     <form class="needs-validation" action="#mqttConfig" method="POST" |  | ||||
|           onsubmit="mqttSettings('mqttConfig'); return false"> |  | ||||
|         <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</label> |  | ||||
|             <input type="text" class="form-control" id="mqttServer" minlength="7" maxlength="%MQTT_SERVER_LENGTH%" |  | ||||
|                    placeholder="z.B. 192.168.2.89" name="mqttServer" value="%MQTT_SERVER%"> |  | ||||
|             <label for="mqttUser">MQTT-Benutzername (optional):</label> |  | ||||
|             <input type="text" class="form-control" id="mqttUser" maxlength="%MQTT_USER_LENGTH%" |  | ||||
|                    placeholder="Benutzername" name="mqttUser" value="%MQTT_USER%"> |  | ||||
|             <label for="mqttPwd">Passwort (optional):</label> |  | ||||
|             <input type="password" class="form-control" id="mqttPwd" maxlength="%MQTT_PWD_LENGTH%" |  | ||||
|                    placeholder="Passwort" name="mqttPwd" value="%MQTT_PWD%"> |  | ||||
|         </div> |  | ||||
|         <button type="reset" class="btn btn-secondary">Reset</button> |  | ||||
|         <button type="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container" id="ftpConfig"> |  | ||||
|     <h2>FTP-Konfiguration</h2> |  | ||||
|     <form action="#ftpConfig" method="POST" onsubmit="ftpSettings('ftpConfig'); return false"> |  | ||||
|         <div class="form-group col-md-6"> |  | ||||
|             <label for="ftpUser">FTP-Benutzername:</label> |  | ||||
|             <input type="text" class="form-control" id="ftpUser" maxlength="%FTP_USER_LENGTH%" |  | ||||
|                    placeholder="Benutzername" name="ftpUser" value="%FTP_USER%" required> |  | ||||
|             <label for="pwd">Passwort:</label> |  | ||||
|             <input type="password" class="form-control" id="ftpPwd" maxlength="%FTP_PWD_LENGTH%" 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">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container my-5" id="generalConfig"> |  | ||||
|     <h2>Allgemeine Konfiguration</h2> |  | ||||
|     <form action="#generalConfig" method="POST" onsubmit="genSettings('generalConfig'); return false"> |  | ||||
|         <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="maxVolumeSpeaker">Maximale Lautstärke (Lautsprecher)</label> |  | ||||
|             <input type="number" min="1" max="21" class="form-control" id="maxVolumeSpeaker" name="maxVolumeSpeaker" |  | ||||
|                    value="%MAX_VOLUME_SPEAKER%" required> |  | ||||
|             <label for="maxVolumeHeadphone">Maximale Lautstärke (Kopfhörer)</label> |  | ||||
|             <input type="number" min="1" max="21" class="form-control" id="maxVolumeHeadphone" name="maxVolumeHeadphone" |  | ||||
|                    value="%MAX_VOLUME_HEADPHONE%" 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_BRIGHTNESS%" 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_BRIGHTNESS%" 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> |  | ||||
|         <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="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <div class="container my-5" id="importNvs"> |  | ||||
|     <h2>NVS-Importer</h2> |  | ||||
|     <form action="/upload" enctype="multipart/form-data" method="POST"> |  | ||||
|         <div class="form-group"> |  | ||||
|             <label for="nvsUpload">Hier kann eine Backup-Datei importiert werden.</label> |  | ||||
|             <input type="file" class="form-control-file" id="nvsUpload" name="nvsUpload" accept=".txt"> |  | ||||
|         </div> |  | ||||
|         <button type="submit" class="btn btn-primary">Absenden</button> |  | ||||
|     </form> |  | ||||
|     <div class="messages col-md-6 my-2"></div> |  | ||||
| </div> |  | ||||
| <script type="text/javascript"> |  | ||||
|     var DEBUG = false; |  | ||||
|     var lastIdclicked = ''; |  | ||||
|     var host = $(location).attr('hostname'); |  | ||||
| 
 |  | ||||
|     if (DEBUG) { |  | ||||
|         host = "192.168.178.112"; |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     toastr.options = { |  | ||||
|         "closeButton": false, |  | ||||
|         "debug": false, |  | ||||
|         "newestOnTop": false, |  | ||||
|         "progressBar": false, |  | ||||
|         "positionClass": "toast-top-right", |  | ||||
|         "preventDuplicates": false, |  | ||||
|         "onclick": null, |  | ||||
|         "showDuration": "300", |  | ||||
|         "hideDuration": "1000", |  | ||||
|         "timeOut": "5000", |  | ||||
|         "extendedTimeOut": "1000", |  | ||||
|         "showEasing": "swing", |  | ||||
|         "hideEasing": "linear", |  | ||||
|         "showMethod": "fadeIn", |  | ||||
|         "hideMethod": "fadeOut" |  | ||||
|     }; |  | ||||
| 
 |  | ||||
|     function postRendering(event, data) { |  | ||||
|         Object.keys(data.instance._model.data).forEach(function (key, index) { |  | ||||
| 
 |  | ||||
|             var cur = data.instance.get_node(data.instance._model.data[key]); |  | ||||
|             var lastFolder = cur['id'].split('/').filter(function (el) { |  | ||||
|                 return el.trim().length > 0; |  | ||||
|             }).pop(); |  | ||||
|             if ((/\.(mp3|MP3|ogg|wav|WAV|OGG|wma|WMA|acc|ACC|flac|FLAC)$/i).test(lastFolder)) { |  | ||||
|                 data.instance.set_type(data.instance._model.data[key], 'audio'); |  | ||||
|             } else { |  | ||||
|                 if (data.instance._model.data[key]['type'] == "file") { |  | ||||
|                     data.instance.disable_node(data.instance._model.data[key]); |  | ||||
|                 } |  | ||||
|             } |  | ||||
|             data.instance.rename_node(data.instance._model.data[key], lastFolder); |  | ||||
|         }); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function renderFileTree() { |  | ||||
| 
 |  | ||||
|         var filesURI = "/files"; |  | ||||
|         if (DEBUG) { |  | ||||
|             filesURI = "http://" + host + "/files"; |  | ||||
|         } |  | ||||
|         $('#filetree').jstree({ |  | ||||
|             'core': { |  | ||||
|                 'check_callback': true, |  | ||||
|                 'data': { |  | ||||
|                     url: filesURI, |  | ||||
|                     error: function (XMLHttpRequest, textStatus, errorThrown) { |  | ||||
|                         $('#j1_loading').hide(); |  | ||||
|                         $("#refreshAction").hide(); |  | ||||
|                         $('#filetree').html("<div class='clickForRefresh' ><i class='fas fa-sync fa-1x'><span id='#clickForRefresh' > Dateien suchen.</span></div>"); |  | ||||
|                         $('#filetree').on("click", function () { |  | ||||
|                             refreshFileList(); |  | ||||
|                         }); |  | ||||
|                         toastr.error("Die Verzeichnis-Liste konnte nicht geladen werden."); |  | ||||
|                     } |  | ||||
|                 }, |  | ||||
| 
 |  | ||||
|             }, |  | ||||
|             'types': { |  | ||||
|                 'folder': { |  | ||||
|                     'icon': "fa fa-folder" |  | ||||
|                 }, |  | ||||
|                 'file': { |  | ||||
|                     'icon': "fa fa-file" |  | ||||
|                 }, |  | ||||
|                 'audio': { |  | ||||
|                     'icon': "fa fa-file-audio" |  | ||||
|                 }, |  | ||||
|                 'default': { |  | ||||
|                     'icon': "fa fa-folder" |  | ||||
|                 } |  | ||||
|             }, |  | ||||
|             'plugins': ["themes", "types"] |  | ||||
|         }).bind('loaded.jstree', function (event, data) { |  | ||||
|             postRendering(event, data); |  | ||||
|             if ((data.instance._model.data['#']['children'].length == 0)) { |  | ||||
|                 toastr.info("Der SD-Karten-Index muss erzeugt werden."); |  | ||||
|             } |  | ||||
|         }).bind('refresh.jstree', function (event, data) { |  | ||||
|             postRendering(event, data); |  | ||||
|         }); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     $('#filetree').on('select_node.jstree', function (e, data) { |  | ||||
|         $('input[name=fileOrUrl]').val(data.node.id); |  | ||||
| 
 |  | ||||
|         if (data.node.type == "folder") { |  | ||||
|             $('.option-folder').show(); |  | ||||
|             $('.option-file').hide(); |  | ||||
|             $('#playMode option').removeAttr('selected').filter('[value=3]').attr('selected', true); |  | ||||
|         } |  | ||||
| 
 |  | ||||
|         if (data.node.type == "audio") { |  | ||||
|             $('.option-file').show(); |  | ||||
|             $('.option-folder').hide(); |  | ||||
|             $('#playMode option').removeAttr('selected').filter('[value=1]').attr('selected', true); |  | ||||
|         } |  | ||||
|     }); |  | ||||
| 
 |  | ||||
|     $('#refreshAction').on("click", function () { |  | ||||
|         refreshFileList(); |  | ||||
|         $("#indexing-progress").show(); |  | ||||
|         $("#refreshAction").hide(); |  | ||||
|     }); |  | ||||
| 
 |  | ||||
|     $('#playMode').on("change", function () { |  | ||||
|         if (this.value == 8) { |  | ||||
|             $('#filebrowser').slideUp(); |  | ||||
|         } else { |  | ||||
|             $('#filebrowser').slideDown(); |  | ||||
|         } |  | ||||
|     }); |  | ||||
| 
 |  | ||||
|     function showFileIndexingState() { |  | ||||
|         $("#indexing-progress").show(); |  | ||||
|         $("#refreshAction").hide(); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function hideFileIndexingState() { |  | ||||
|         $("#indexing-progress").hide(); |  | ||||
|         $("#refreshAction").show(); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     var socket = undefined; |  | ||||
|     var tm; |  | ||||
| 
 |  | ||||
|     function connect() { |  | ||||
|         socket = new WebSocket("ws://" + host + "/ws"); |  | ||||
| 
 |  | ||||
|         socket.onopen = function () { |  | ||||
|             setInterval(ping, 15000); |  | ||||
|         }; |  | ||||
| 
 |  | ||||
|         socket.onclose = function (e) { |  | ||||
|             console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason); |  | ||||
|             socket = null; |  | ||||
|             setTimeout(function () { |  | ||||
|                 connect(); |  | ||||
|             }, 5000); |  | ||||
|         }; |  | ||||
| 
 |  | ||||
|         socket.onerror = function (err) { |  | ||||
|             console.error('Socket encountered error: ', err.message, 'Closing socket'); |  | ||||
|         }; |  | ||||
| 
 |  | ||||
|         socket.onmessage = function(event) { |  | ||||
|           console.log(event.data); |  | ||||
|           var socketMsg = JSON.parse(event.data); |  | ||||
|           if (socketMsg.rfidId != null) { |  | ||||
|               document.getElementById('rfidIdMod').value = socketMsg.rfidId; |  | ||||
|               document.getElementById('rfidIdMusic').value = socketMsg.rfidId; |  | ||||
|               toastr.info("RFID Tag mit "+ socketMsg.rfidId + " erkannt." ); |  | ||||
| 
 |  | ||||
|               $("#rfidIdMusic").effect("highlight", {color:"#abf5af"}, 3000); |  | ||||
|               $("#rfidIdMod").effect("highlight", {color:"#abf5af"}, 3000); |  | ||||
| 
 |  | ||||
|           } if ("status" in socketMsg) { |  | ||||
|               if (socketMsg.status == "ok") { |  | ||||
|                   toastr.success("Aktion erfolgreich ausgeführt." ); |  | ||||
|               } |  | ||||
|           } if ("pong" in socketMsg) { |  | ||||
|               if (socketMsg.pong == 'pong') { |  | ||||
|                   pong(); |  | ||||
|               } |  | ||||
|           } if ("refreshFileList" in socketMsg) { |  | ||||
|               hideFileIndexingState(); |  | ||||
|               toastr.info("Die Dateiliste wurde neu erzeugt!"); |  | ||||
|               $('#filetree').jstree(true).refresh(); |  | ||||
| 
 |  | ||||
|           } |  | ||||
|           if ("indexingState" in socketMsg) { |  | ||||
|               if(socketMsg.indexingState != null) { |  | ||||
|                   $("#currentProcessedFile").text(socketMsg.indexingState); |  | ||||
|                   console.log(socketMsg.indexingState); |  | ||||
|               } |  | ||||
|           } |  | ||||
|       }; |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function ping() { |  | ||||
|         var myObj = { |  | ||||
|             "ping": { |  | ||||
|                 ping: 'ping' |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|         tm = setTimeout(function () { |  | ||||
|             toastr.warning('Die Verbindung zum Tonuino ist unterbrochen! Bitte Seite neu laden.'); |  | ||||
|         }, 5000); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function pong() { |  | ||||
|         clearTimeout(tm); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function refreshFileList(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "refreshFileList": true |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         $("#refreshAction").hide(); |  | ||||
|         socket.send(myJSON); |  | ||||
|         showFileIndexingState(); |  | ||||
|     }; |  | ||||
| 
 |  | ||||
|     function genSettings(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "general": { |  | ||||
|                 iVol: document.getElementById('initialVolume').value, |  | ||||
|                 mVolSpeaker: document.getElementById('maxVolumeSpeaker').value, |  | ||||
|                 mVolHeadphone: document.getElementById('maxVolumeHeadphone').value, |  | ||||
|                 iBright: document.getElementById('initBrightness').value, |  | ||||
|                 nBright: document.getElementById('nightBrightness').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); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function ftpSettings(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "ftp": { |  | ||||
|                 ftpUser: document.getElementById('ftpUser').value, |  | ||||
|                 ftpPwd: document.getElementById('ftpPwd').value |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function mqttSettings(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var val; |  | ||||
|         if (document.getElementById('mqttEnable').checked) { |  | ||||
|             val = document.getElementById('mqttEnable').value; |  | ||||
|         } else { |  | ||||
|             val = 0; |  | ||||
|         } |  | ||||
|         var myObj = { |  | ||||
|             "mqtt": { |  | ||||
|                 mqttEnable: val, |  | ||||
|                 mqttServer: document.getElementById('mqttServer').value, |  | ||||
|                 mqttUser: document.getElementById('mqttUser').value, |  | ||||
|                 mqttPwd: document.getElementById('mqttPwd').value |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function rfidMods(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "rfidMod": { |  | ||||
|                 rfidIdMod: document.getElementById('rfidIdMod').value, |  | ||||
|                 modId: document.getElementById('modId').value |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function removeTrSlash(str) { |  | ||||
|         if (str.substr(-1) === '/') { |  | ||||
|             return str.substr(0, str.length - 1); |  | ||||
|         } |  | ||||
|         return str; |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function rfidAssign(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "rfidAssign": { |  | ||||
|                 rfidIdMusic: document.getElementById('rfidIdMusic').value, |  | ||||
|                 fileOrUrl: removeTrSlash(document.getElementById('fileOrUrl').value), |  | ||||
|                 playMode: document.getElementById('playMode').value |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     function wifiConfig(clickedId) { |  | ||||
|         lastIdclicked = clickedId; |  | ||||
|         var myObj = { |  | ||||
|             "wifiConfig": { |  | ||||
|                 ssid: document.getElementById('ssid').value, |  | ||||
|                 pwd: document.getElementById('pwd').value, |  | ||||
|                 hostname: document.getElementById('hostname').value |  | ||||
|             } |  | ||||
|         }; |  | ||||
|         var myJSON = JSON.stringify(myObj); |  | ||||
|         socket.send(myJSON); |  | ||||
|     } |  | ||||
| 
 |  | ||||
|     $(document).ready(function () { |  | ||||
|         connect(); |  | ||||
|         renderFileTree(); |  | ||||
| 
 |  | ||||
|         $(function () { |  | ||||
|             $('[data-toggle="tooltip"]').tooltip(); |  | ||||
|         }); |  | ||||
|     }); |  | ||||
| </script> |  | ||||
| </body> |  | ||||
| </html> |  | ||||
| @ -1,61 +1,74 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
| #!/usr/bin/python | #!/usr/bin/python | ||||
| import re |  | ||||
| 
 |  | ||||
| content = '' |  | ||||
| content2 = '' |  | ||||
| contentEN = '' |  | ||||
| content2EN = '' |  | ||||
| 
 |  | ||||
| # TODO: Add a JS Minifier python lib |  | ||||
| with open('html/website.html', 'r') as r: |  | ||||
|     data = r.read() |  | ||||
|     data = data.replace('\n', '\\\n') |  | ||||
|     data = data.replace('\"', '\\"') |  | ||||
|     data = data.replace('\\d', '\\\d') |  | ||||
|     data = data.replace('\\.', '\\\.') |  | ||||
|     data = data.replace('\\^', '\\\\^') |  | ||||
|     data = data.replace('%;', '%%;') |  | ||||
|     content += data |  | ||||
| 
 |  | ||||
| with open('src/websiteMgmt.h', 'w') as w: |  | ||||
|     w.write("static const char mgtWebsite[] PROGMEM = \"") |  | ||||
|     w.write(content) |  | ||||
|     w.write("\";") |  | ||||
| 
 |  | ||||
| with open('html/website_EN.html', 'r') as ren: |  | ||||
|     data = ren.read().replace('\n', '\\\n') |  | ||||
|     data = data.replace('\"', '\\"') |  | ||||
|     data = data.replace('\\d', '\\\d') |  | ||||
|     data = data.replace('\\.', '\\\.') |  | ||||
|     data = data.replace('\\^', '\\\\^') |  | ||||
|     contentEN += data |  | ||||
| 
 |  | ||||
| with open('src/websiteMgmt_EN.h', 'w') as wen: |  | ||||
|     wen.write("static const char mgtWebsite[] PROGMEM = \"") |  | ||||
|     wen.write(contentEN) |  | ||||
|     wen.write("\";") |  | ||||
| 
 |  | ||||
| with open('html/websiteBasic.html', 'r') as r2: |  | ||||
|     data = r2.read().replace('\n', '\\\n') |  | ||||
|     data = data.replace('\"', '\\"') |  | ||||
|     content2 += data |  | ||||
| 
 |  | ||||
| with open('src/websiteBasic.h', 'w') as w2: |  | ||||
|     w2.write("static const char basicWebsite[] PROGMEM = \"") |  | ||||
|     w2.write(content2) |  | ||||
|     w2.write("\";") |  | ||||
| 
 |  | ||||
| with open('html/websiteBasic_EN.html', 'r') as r2en: |  | ||||
|     data = r2en.read().replace('\n', '\\\n') |  | ||||
|     data = data.replace('\"', '\\"') |  | ||||
|     content2EN += data |  | ||||
| 
 |  | ||||
| with open('src/websiteBasic_EN.h', 'w') as w2en: |  | ||||
|     w2en.write("static const char basicWebsite[] PROGMEM = \"") |  | ||||
|     w2en.write(content2EN) |  | ||||
|     w2en.write("\";") |  | ||||
| 
 |  | ||||
| r.close() |  | ||||
| w.close() |  | ||||
| r2.close() |  | ||||
| w2.close() |  | ||||
|  | ### | ||||
|  | # Use this script for creating PROGMEM header files from html files. | ||||
|  | # needs pip install requests | ||||
|  | ## | ||||
|  | # html file base names | ||||
|  | import requests | ||||
|  | import argparse | ||||
|  | 
 | ||||
|  | def str2bool(v): | ||||
|  |     if isinstance(v, bool): | ||||
|  |         return v | ||||
|  |     if v.lower() in ('yes', 'true', 't', 'y', '1'): | ||||
|  |         return True | ||||
|  |     elif v.lower() in ('no', 'false', 'f', 'n', '0'): | ||||
|  |         return False | ||||
|  |     else: | ||||
|  |         raise argparse.ArgumentTypeError('Boolean value expected.') | ||||
|  | 
 | ||||
|  | HTML_FILES = ["management","management_EN", "accesspoint", "accesspoint_EN"] | ||||
|  | 
 | ||||
|  | class htmlHeaderProcessor(object): | ||||
|  | 
 | ||||
|  |     """ | ||||
|  |     Returns a minified HTML string, uses html-minifier.com api. | ||||
|  |     """ | ||||
|  |     def minifyHTML(self, filename): | ||||
|  |         with open('html/' + filename + '.html', 'r') as r: | ||||
|  |             data = r.read() | ||||
|  |             return requests.post('https://html-minifier.com/raw', data=dict(input=data)).text.encode('utf8') | ||||
|  | 
 | ||||
|  |     def escape_html(self, data): | ||||
|  |         data = data.replace('\n', '\\\n') | ||||
|  |         data = data.replace('\"', '\\"') | ||||
|  |         data = data.replace('\\d', '\\\d') | ||||
|  |         data = data.replace('\\.', '\\\.') | ||||
|  |         data = data.replace('\\^', '\\\\^') | ||||
|  |         data = data.replace('%;', '%%;') | ||||
|  |         return data | ||||
|  | 
 | ||||
|  |     def html_to_c_header(self, filename): | ||||
|  |         content = "" | ||||
|  |         with open('html/' + filename + '.html', 'r') as r: | ||||
|  |             data = r.read() | ||||
|  |             content += self.escape_html(data) | ||||
|  |         return content | ||||
|  | 
 | ||||
|  | 
 | ||||
|  |     def write_header_file(self, filename, content): | ||||
|  |         with open('src/HTML' + filename + '.h', 'w') as w: | ||||
|  |             varname = filename.split('_')[0] | ||||
|  |             w.write("static const char " + varname + "_HTML[] PROGMEM = \"") | ||||
|  |             w.write(content) | ||||
|  |             w.write("\";") | ||||
|  | 
 | ||||
|  |     def main(self): | ||||
|  |         parser = argparse.ArgumentParser(description='Create c code PROGMEM header files from HTML files.') | ||||
|  |         parser.add_argument("--minify", type=str2bool, nargs='?', | ||||
|  |                             const=True, default=False, | ||||
|  |                             help="Minify HTML Code") | ||||
|  |         args = parser.parse_args() | ||||
|  | 
 | ||||
|  |         for file in HTML_FILES: | ||||
|  |             if args.minify: | ||||
|  | 
 | ||||
|  |                 self.header_file_content = self.minifyHTML(file) | ||||
|  |                 self.header_file_content = self.escape_html(self.header_file_content) | ||||
|  |             else: | ||||
|  |                 self.header_file_content = self.html_to_c_header(file) | ||||
|  |             self.write_header_file(file, self.header_file_content) | ||||
|  | 
 | ||||
|  | if __name__ == '__main__': | ||||
|  |     htmlHeaderProcessor().main() | ||||
| @ -1,4 +1,4 @@ | |||||
| static const char basicWebsite[] PROGMEM = "<!DOCTYPE html>\ |  | ||||
|  | static const char accesspoint_HTML[] PROGMEM = "<!DOCTYPE html>\ | ||||
| <html>\ | <html>\ | ||||
|     <head>\ |     <head>\ | ||||
|         <title>Wifi-configuration</title>\ |         <title>Wifi-configuration</title>\ | ||||
| @ -0,0 +1,728 @@ | |||||
|  | static const char management_HTML[] 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/tonuino/css/bootstrap.min.css\">\ | ||||
|  |     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css\"/>\ | ||||
|  |     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css\"/>\ | ||||
|  |     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css\"/>\ | ||||
|  |     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/css/bootstrap-slider.min.css\" />\ | ||||
|  |     <script src=\"https://ts-cs.de/tonuino/js/jquery.min.js\"></script>\ | ||||
|  |     <script src=\"https://code.jquery.com/ui/1.12.0/jquery-ui.min.js\"></script>\ | ||||
|  |     <script src=\"https://ts-cs.de/tonuino/js/popper.min.js\"></script>\ | ||||
|  |     <script src=\"https://ts-cs.de/tonuino/js/bootstrap.min.js\"></script>\ | ||||
|  |     <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js\"></script>\ | ||||
|  |     <script src=\"https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js\"></script>\ | ||||
|  |     <script src=\"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/11.0.2/bootstrap-slider.min.js\"></script>\ | ||||
|  |     <style type=\"text/css\">\ | ||||
|  |         .filetree {\ | ||||
|  |             border: 1px solid black;\ | ||||
|  |             height: 200px;\ | ||||
|  |             margin: 0em 0em 1em 0em;\ | ||||
|  |             overflow-y: scroll;\ | ||||
|  |         }\ | ||||
|  |         .slider.slider-horizontal {\ | ||||
|  |             width: 60%%;\ | ||||
|  |             margin-left: 1em;\ | ||||
|  |             margin-right: 1em;\ | ||||
|  | \ | ||||
|  |         }\ | ||||
|  |         .slider-handle{\ | ||||
|  |             height: 30px;\ | ||||
|  |             width: 30px;\ | ||||
|  |             top: -5px;\ | ||||
|  |         }\ | ||||
|  |      \ | ||||
|  |         legend.scheduler-border {\ | ||||
|  |             width:inherit; /* Or auto */\ | ||||
|  |             padding:0 10px; /* To give a bit of padding on the left and right */\ | ||||
|  |             border-bottom:none;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .icon-pos{\ | ||||
|  |             top: 0.3em;\ | ||||
|  |             position: relative;\ | ||||
|  |          }\ | ||||
|  |         .reboot{\ | ||||
|  |             color:white;\ | ||||
|  |         }\ | ||||
|  |         .reboot:hover{\ | ||||
|  |             color: orange;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .fa-sync:hover {\ | ||||
|  |             color: #666666;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .clickForRefresh {\ | ||||
|  |             text-align: center;\ | ||||
|  |             color: gray;\ | ||||
|  |             cursor: pointer;\ | ||||
|  |             margin-top: 5em;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .clickForRefresh:hover {\ | ||||
|  |             color: darkgray;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .filetree-container {\ | ||||
|  |             position: relative;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .indexing-progress {\ | ||||
|  |             width: 100%%;\ | ||||
|  |             height: 100%%;\ | ||||
|  |             position: absolute;\ | ||||
|  |             top: 0;\ | ||||
|  |             left: 0;\ | ||||
|  |             opacity: 0.7;\ | ||||
|  |             display: none;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .refreshAction{\ | ||||
|  |             text-align: right;\ | ||||
|  |             font-size: 0.8em;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .refreshAction:hover{\ | ||||
|  |             cursor: pointer;\ | ||||
|  |             color: darkgray;\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         .overlay {\ | ||||
|  |             z-index: 9;\ | ||||
|  |             opacity: 0.8;\ | ||||
|  |             background: #1a1919;\ | ||||
|  |             height: 200px;\ | ||||
|  |             display: none;\ | ||||
|  |             width: 100%%;\ | ||||
|  |         }\ | ||||
|  |     </style>\ | ||||
|  | </head>\ | ||||
|  | <body>\ | ||||
|  | <nav class=\"navbar navbar-expand-sm bg-primary navbar-dark\">\ | ||||
|  |     <div class=\"col-md-12\">\ | ||||
|  |     <a class=\"float-left navbar-brand\">\ | ||||
|  |         <img src=\"https://raw.githubusercontent.com/biologist79/Tonuino-ESP32-I2S/master/html/tonuino_logo.png\"\ | ||||
|  |              width=\"30\" height=\"30\" class=\"d-inline-block align-top\" alt=\"\"/>\ | ||||
|  |         Tonuino\ | ||||
|  |     </a>\ | ||||
|  | \ | ||||
|  |     <a class=\"reboot float-right nav-link\" href=\"/restart\"><i class=\"fas fa-power-off\"></i> Neustart</a>\ | ||||
|  |     </div>\ | ||||
|  | </nav>\ | ||||
|  | <br/>\ | ||||
|  |     <nav>\ | ||||
|  |         <div class=\"container nav nav-tabs\" id=\"nav-tab\" role=\"tablist\">\ | ||||
|  |             <a class=\"nav-item nav-link active\" id=\"nav-rfid-tab\" data-toggle=\"tab\" href=\"#nav-rfid\" role=\"tab\" aria-controls=\"nav-rfid\" aria-selected=\"true\"><i class=\"fas fa-dot-circle\"></i> RFID</a>\ | ||||
|  |             <a class=\"nav-item nav-link\" id=\"nav-wifi-tab\" data-toggle=\"tab\" href=\"#nav-wifi\" role=\"tab\" aria-controls=\"nav-wifi\" aria-selected=\"false\"><i class=\"fas fa-wifi\"></i><span class=\".d-sm-none .d-md-block\"> WLAN</span></a>\ | ||||
|  |             <a class=\"nav-item nav-link\" id=\"nav-mqtt-tab\" data-toggle=\"tab\" href=\"#nav-mqtt\" role=\"tab\" aria-controls=\"nav-mqtt\" aria-selected=\"false\"><i class=\"fas fa-network-wired\"></i> MQTT</a>\ | ||||
|  |             <a class=\"nav-item nav-link\" id=\"nav-ftp-tab\" data-toggle=\"tab\" href=\"#nav-ftp\" role=\"tab\" aria-controls=\"nav-ftp\" aria-selected=\"false\"><i class=\"fas fa-folder\"></i> FTP</a>\ | ||||
|  |             <a class=\"nav-item nav-link\" id=\"nav-general-tab\" data-toggle=\"tab\" href=\"#nav-general\" role=\"tab\" aria-controls=\"nav-general\" aria-selected=\"false\"><i class=\"fas fa-sliders-h\"></i> Allgemein</a>\ | ||||
|  |             <a class=\"nav-item nav-link\" id=\"nav-tools-tab\" data-toggle=\"tab\" href=\"#nav-tools\" role=\"tab\" aria-controls=\"nav-tools\" aria-selected=\"false\"><i class=\"fas fa-wrench\"></i> Tools</a>\ | ||||
|  |         </div>\ | ||||
|  |     </nav>\ | ||||
|  | <br>\ | ||||
|  | <div class=\"tab-content\" id=\"nav-tabContent\">\ | ||||
|  |     <div class=\"tab-pane fade\" id=\"nav-wifi\" role=\"tabpanel\" aria-labelledby=\"nav-wifi-tab\">\ | ||||
|  |         <div class=\"container\" id=\"wifiConfig\">\ | ||||
|  |             <form action=\"#wifiConfig\" method=\"POST\" onsubmit=\"wifiConfig('wifiConfig'); return false\">\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <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>\ | ||||
|  |                     <label for=\"hostname\">Tonuino-Name (Hostname):</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"hostname\" placeholder=\"tonuino\" name=\"hostname\"\ | ||||
|  |                            value=\"%HOSTNAME%\" pattern=\"^[^-\\.]{2,32}\" required>\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  |     <div class=\"tab-pane fade show active\" id=\"nav-rfid\" role=\"tabpanel\" aria-labelledby=\"nav-rfid-tab\">\ | ||||
|  |         <div class=\"container\" id=\"rfidMusicTags\">\ | ||||
|  |             <fieldset>\ | ||||
|  |                 <legend>RFID-Zuweisungen</legend>\ | ||||
|  |             <form action=\"#rfidMusicTags\" method=\"POST\" onsubmit=\"rfidAssign('rfidMusicTags'); return false\">\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <label for=\"rfidIdMusic\">RFID-Chip-Nummer (12-stellig)</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"rfidIdMusic\" maxlength=\"12\" pattern=\"[0-9]{12}\"\ | ||||
|  |                            placeholder=\"%RFID_TAG_ID%\" name=\"rfidIdMusic\" required>\ | ||||
|  |                     <label for=\"fileOrUrl\">Datei, Verzeichnis oder URL (^ und # als Zeichen nicht erlaubt)</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"fileOrUrl\" maxlength=\"255\" placeholder=\"z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3\" pattern=\"^[^\\^#]+$\" name=\"fileOrUrl\" required>\ | ||||
|  |                     <div class=\"filetree-container\">\ | ||||
|  |                         <div id=\"filebrowser\">\ | ||||
|  |                             <div class=\"filetree demo\" id=\"filetree\"></div>\ | ||||
|  |                             <div class=\"refreshAction\">\ | ||||
|  |                                 <span id=\"refreshAction\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Datei Liste aktualisieren.\"><i class=\"fas fa-sync fa-1x\"></i> Dateiliste aktualisieren</span>\ | ||||
|  |                             </div>\ | ||||
|  |                         </div>\ | ||||
|  |                         <div id=\"indexing-progress\" class=\"indexing-progress overlay\">\ | ||||
|  |                             <div style=\"text-align: center; color:white; margin-top:2em;\">\ | ||||
|  |                                 <div><i class=\"fas fa-sync fa-spin fa-2x\"></i> <br><br>  Der Prozess kann mehrere Minuten dauern...</div>\ | ||||
|  |                                 <div id=\"currentProcessedFile\"></div>\ | ||||
|  |                             </div>\ | ||||
|  |                         </div>\ | ||||
|  |                     </div>\ | ||||
|  |                     <label for=\"playMode\">Abspielmodus</label>\ | ||||
|  |                     <select class=\"form-control\" id=\"playMode\" name=\"playMode\">\ | ||||
|  |                         <option class=\"option-file\" value=\"1\">Einzelner Titel</option>\ | ||||
|  |                         <option class=\"option-file\" value=\"2\">Einzelner Titel (Endlosschleife)</option>\ | ||||
|  |                         <option class=\"option-file-and-folder\" value=\"3\">Hörbuch</option>\ | ||||
|  |                         <option class=\"option-file-and-folder\" value=\"4\">Hörbuch (Endlosschleife)</option>\ | ||||
|  |                         <option class=\"option-folder\" value=\"5\">Alle Titel eines Verzeichnis (sortiert)</option>\ | ||||
|  |                         <option class=\"option-folder\" value=\"6\">Alle Titel eines Verzeichnis (zufällig)</option>\ | ||||
|  |                         <option class=\"option-folder\" value=\"7\">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option>\ | ||||
|  |                         <option class=\"option-folder\" value=\"9\">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>\ | ||||
|  |                         <option class=\"option-stream\" value=\"8\">Webradio</option>\ | ||||
|  |                     </select>\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |             </fieldset>\ | ||||
|  |         </div>\ | ||||
|  | \ | ||||
|  |         <br>\ | ||||
|  |         <br>\ | ||||
|  |         <div class=\"container\" id=\"rfidModTags\">\ | ||||
|  |             <fieldset>\ | ||||
|  |                 <legend>RFID-Modifkationen</legend>\ | ||||
|  |             <form class=\"needs-validation\" action=\"#rfidModTags\" method=\"POST\" onsubmit=\"rfidMods('rfidModTags'); return false\">\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <label for=\"rfidIdMod\">RFID-Chip-Nummer (12-stellig)</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"rfidIdMod\" maxlength=\"12\" pattern=\"[0-9]{12}\"\ | ||||
|  |                            placeholder=\"%RFID_TAG_ID%\" name=\"rfidIdMod\" required>\ | ||||
|  |                     <div class=\"invalid-feedback\">\ | ||||
|  |                         Bitte eine 12-stellige Zahl eingeben.\ | ||||
|  |                     </div>\ | ||||
|  |                     <label for=\"modId\">Konfiguraiton</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=\"107\">Schlafen nach fünf Titeln</option>\ | ||||
|  |                         <option value=\"110\">Wiederhole Playlist (endlos)</option>\ | ||||
|  |                         <option value=\"111\">Wiederhole Titel (endlos)</option>\ | ||||
|  |                         <option value=\"112\">Dimme LEDs (Nachtmodus)</option>\ | ||||
|  |                         <option value=\"130\">Aktiviere/deaktive WLAN</option>\ | ||||
|  |                     </select>\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |             </fieldset>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  |     <div class=\"tab-pane fade\" id=\"nav-mqtt\" role=\"tabpanel\" aria-labelledby=\"nav-mqtt-tab\">\ | ||||
|  |         <div class=\"container\" id=\"mqttConfig\">\ | ||||
|  | \ | ||||
|  |             <form class=\"needs-validation\" action=\"#mqttConfig\" method=\"POST\"\ | ||||
|  |                   onsubmit=\"mqttSettings('mqttConfig'); return false\">\ | ||||
|  |                 <div class=\"form-check col-md-12\">\ | ||||
|  |                     <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-12\">\ | ||||
|  |                     <label for=\"mqttServer\">MQTT-Server</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"mqttServer\" minlength=\"7\" maxlength=\"%MQTT_SERVER_LENGTH%\"\ | ||||
|  |                            placeholder=\"z.B. 192.168.2.89\" name=\"mqttServer\" value=\"%MQTT_SERVER%\">\ | ||||
|  |                     <label for=\"mqttUser\">MQTT-Benutzername (optional):</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"mqttUser\" maxlength=\"%MQTT_USER_LENGTH%\"\ | ||||
|  |                            placeholder=\"Benutzername\" name=\"mqttUser\" value=\"%MQTT_USER%\">\ | ||||
|  |                     <label for=\"mqttPwd\">Passwort (optional):</label>\ | ||||
|  |                     <input type=\"password\" class=\"form-control\" id=\"mqttPwd\" maxlength=\"%MQTT_PWD_LENGTH%\"\ | ||||
|  |                            placeholder=\"Passwort\" name=\"mqttPwd\" value=\"%MQTT_PWD%\">\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  |     <div class=\"tab-pane fade\" id=\"nav-ftp\" role=\"tabpanel\" aria-labelledby=\"nav-ftp-tab\">\ | ||||
|  |         <div class=\"container\" id=\"ftpConfig\">\ | ||||
|  | \ | ||||
|  |             <form action=\"#ftpConfig\" method=\"POST\" onsubmit=\"ftpSettings('ftpConfig'); return false\">\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <label for=\"ftpUser\">FTP-Benutzername:</label>\ | ||||
|  |                     <input type=\"text\" class=\"form-control\" id=\"ftpUser\" maxlength=\"%FTP_USER_LENGTH%\"\ | ||||
|  |                            placeholder=\"Benutzername\" name=\"ftpUser\" value=\"%FTP_USER%\" required>\ | ||||
|  |                     <label for=\"pwd\">Passwort:</label>\ | ||||
|  |                     <input type=\"password\" class=\"form-control\" id=\"ftpPwd\" maxlength=\"%FTP_PWD_LENGTH%\" placeholder=\"Passwort\"\ | ||||
|  |                            name=\"ftpPwd\" value=\"%FTP_PWD%\" required>\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  | \ | ||||
|  |     <div class=\"tab-pane fade\" id=\"nav-general\" role=\"tabpanel\" aria-labelledby=\"nav-general-tab\">\ | ||||
|  |         <div class=\"container\" id=\"generalConfig\">\ | ||||
|  | \ | ||||
|  |             <form action=\"#generalConfig\" method=\"POST\" onsubmit=\"genSettings('generalConfig'); return false\">\ | ||||
|  |                     <div class=\"form-group col-md-12\">\ | ||||
|  |                     <fieldset>\ | ||||
|  |                             <legend class=\"w-auto\">Lautstärke</legend>\ | ||||
|  |                     <label for=\"initialVolume\">Nach dem Einschalten</label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                     <i class=\"fas fa-volume-down fa-2x .icon-pos\"></i> <input data-provide=\"slider\" type=\"number\" data-slider-min=\"1\" data-slider-max=\"21\" min=\"1\" max=\"21\" class=\"form-control\" id=\"initialVolume\" name=\"initialVolume\"\ | ||||
|  |                         data-slider-value=\"%INIT_VOLUME%\"  value=\"%INIT_VOLUME%\" required>  <i class=\"fas fa-volume-up fa-2x .icon-pos\"></i></div>\ | ||||
|  |                         <br>\ | ||||
|  |                     <label for=\"maxVolumeSpeaker\">Maximal Lautsprecher</label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                      <i class=\"fas fa-volume-down fa-2x .icon-pos\"></i>   <input data-provide=\"slider\" type=\"number\" data-slider-min=\"1\" data-slider-max=\"21\" min=\"1\" max=\"21\" class=\"form-control\" id=\"maxVolumeSpeaker\" name=\"maxVolumeSpeaker\"\ | ||||
|  |                         data-slider-value=\"%MAX_VOLUME_SPEAKER%\"  value=\"%MAX_VOLUME_SPEAKER%\" required>  <i class=\"fas fa-volume-up fa-2x .icon-pos\"></i>\ | ||||
|  |                         </div>\ | ||||
|  |                         <br>\ | ||||
|  |                     <label for=\"maxVolumeHeadphone\">Maximal Kopfhörer</label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                     <i class=\"fas fa-volume-down fa-2x .icon-pos\"></i> <input data-provide=\"slider\" type=\"number\" data-slider-min=\"1\" data-slider-max=\"21\" min=\"1\" max=\"21\" class=\"form-control\" id=\"maxVolumeHeadphone\" name=\"maxVolumeHeadphone\"\ | ||||
|  |                          data-slider-value=\"%MAX_VOLUME_HEADPHONE%\" value=\"%MAX_VOLUME_HEADPHONE%\" required>  <i class=\"fas fa-volume-up fa-2x .icon-pos\"></i>\ | ||||
|  |                         </div>\ | ||||
|  |                 </fieldset>\ | ||||
|  |                 </div>\ | ||||
|  | <br>\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <fieldset >\ | ||||
|  |                         <legend  class=\"w-auto\">Neopixel (Helligkeit)</legend>\ | ||||
|  |                     <label for=\"initBrightness\">Nach dem Einschalten:</label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                             <i class=\"far fa-sun fa-2x .icon-pos\"></i>\ | ||||
|  |                         <input data-provide=\"slider\" type=\"number\" data-slider-min=\"0\" data-slider-max=\"255\" min=\"0\" max=\"255\" class=\"form-control\" id=\"initBrightness\" name=\"initBrightness\"\ | ||||
|  |                                data-slider-value=\"%INIT_LED_BRIGHTNESS%\"  value=\"%INIT_LED_BRIGHTNESS%\" required><i class=\"fas fa-sun fa-2x .icon-pos\"></i>\ | ||||
|  |                         </div>\ | ||||
|  | \ | ||||
|  |                     <label for=\"nightBrightness\">Im Nachtmodus</label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                         <i class=\"far fa-sun fa-2x .icon-pos\"></i><input data-provide=\"slider\" type=\"number\" data-slider-min=\"0\" data-slider-max=\"255\" min=\"0\" max=\"255\" class=\"form-control\" id=\"nightBrightness\" name=\"nightBrightness\" data-slider-value=\"%NIGHT_LED_BRIGHTNESS%\" value=\"%NIGHT_LED_BRIGHTNESS%\" required><i class=\"fas fa-sun fa-2x .icon-pos\"></i>\ | ||||
|  |                         </div>\ | ||||
|  |                     </fieldset>\ | ||||
|  |                 </div>\ | ||||
|  | <br>\ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <fieldset>\ | ||||
|  |                         <legend>Deep Sleep</legend>\ | ||||
|  | \ | ||||
|  |                         <label for=\"inactivityTime\">Inaktivität nach (in Minuten)</label>\ | ||||
|  |                         <div class=\"text-center\"><i class=\"fas fa-hourglass-start fa-2x .icon-pos\"></i> <input type=\"number\" data-provide=\"slider\" data-slider-min=\"0\" data-slider-max=\"30\" min=\"1\" max=\"120\" class=\"form-control\" id=\"inactivityTime\" name=\"inactivityTime\"\ | ||||
|  |                          data-slider-value=\"%MAX_INACTIVITY%\"  value=\"%MAX_INACTIVITY%\" required><i class=\"fas fa-hourglass-end fa-2x .icon-pos\"></i></div>\ | ||||
|  |                     </fieldset>\ | ||||
|  |                 </div>\ | ||||
|  | <br>\ | ||||
|  | \ | ||||
|  |                 <div class=\"form-group col-md-12\">\ | ||||
|  |                     <fieldset>\ | ||||
|  |                         <legend>Batterie</legend>\ | ||||
|  |                     <div>Status über Neopixel anzeigen</div>\ | ||||
|  |                         <br>\ | ||||
|  |                     <label for=\"warningLowVoltage\">Spannungsgrenze für Status Anzeige.\ | ||||
|  |                     </label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                         <i class=\"fas fa-battery-quarter fa-2x .icon-pos\"></i> <input  data-provide=\"slider\"  data-slider-step=\"0.1\" data-slider-min=\"3.0\" data-slider-max=\"5.0\"  min=\"3.0\" max=\"5.0\" type=\"text\" class=\"form-control\" id=\"warningLowVoltage\" name=\"warningLowVoltage\"\ | ||||
|  |                         data-slider-value=\"%WARNING_LOW_VOLTAGE%\" value=\"%WARNING_LOW_VOLTAGE%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required> <i class=\"fas fa-battery-three-quarters fa-2x .icon-pos\" fa-2x .icon-pos></i>\ | ||||
|  |                         </div>\ | ||||
|  | <br>\ | ||||
|  |                     <label for=\"voltageIndicatorLow\">Unterer Akkuspannungslevel\ | ||||
|  |                         </label>\ | ||||
|  |                         <div class=\"text-center\">\ | ||||
|  |                         <i class=\"fas fa-battery-quarter fa-2x .icon-pos\"></i> <input data-provide=\"slider\" min=\"2.0\" data-slider-step=\"0.1\"  data-slider-min=\"2.0\" data-slider-max=\"5.0\" max=\"5.0\"type=\"text\" class=\"form-control\" id=\"voltageIndicatorLow\" name=\"voltageIndicatorLow\"\ | ||||
|  |                           data-slider-value=\"%VOLTAGE_INDICATOR_LOW%\"  value=\"%VOLTAGE_INDICATOR_LOW%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required> <i class=\"fas fa-battery-three-quarters fa-2x .icon-pos\" fa-2x .icon-pos></i>\ | ||||
|  |                         </div>\ | ||||
|  |                         <br>\ | ||||
|  |                         <label for=\"voltageIndicatorHigh\">Oberer Akkuspannungslevel</label>\ | ||||
|  | \ | ||||
|  |                             <div class=\"text-center\">\ | ||||
|  |                                 <i class=\"fas fa-battery-quarter fa-2x .icon-pos\"></i><input data-provide=\"slider\" data-slider-step=\"0.1\"  data-slider-min=\"2.0\" data-slider-max=\"5.0\" min=\"2.0\" max=\"5.0\" type=\"text\" class=\"form-control\" id=\"voltageIndicatorHigh\" name=\"voltageIndicatorHigh\"\ | ||||
|  |                            data-slider-value=\"%VOLTAGE_INDICATOR_HIGH%\"  value=\"%VOLTAGE_INDICATOR_HIGH%\" pattern=\"^\\d{1,2}(\\.\\d{1,3})?\" required> <i class=\"fas fa-battery-three-quarters fa-2x .icon-pos\" fa-2x .icon-pos></i>\ | ||||
|  |                         </div>\ | ||||
|  | \ | ||||
|  |                         <br>\ | ||||
|  |                     <label for=\"voltageCheckInterval\"> Interval der Messung (in Minuten)</label>\ | ||||
|  |                         <div class=\"text-center\"><i class=\"fas fa-hourglass-start fa-2x .icon-pos\"></i>\ | ||||
|  |                             <input data-provide=\"slider\" data-slider-min=\"1\" data-slider-max=\"60\" type=\"number\" min=\"1\" max=\"60\" class=\"form-control\" id=\"voltageCheckInterval\"\ | ||||
|  |                                    data-slider-value=\"%VOLTAGE_CHECK_INTERVAL%\"  name=\"voltageCheckInterval\" value=\"%VOLTAGE_CHECK_INTERVAL%\" required><i class=\"fas fa-hourglass-end fa-2x .icon-pos\"></i>\ | ||||
|  |                     </div>\ | ||||
|  | \ | ||||
|  |                     </fieldset>\ | ||||
|  |                 </div>\ | ||||
|  | <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  |     <div class=\"tab-pane fade\" id=\"nav-tools\" role=\"tabpanel\" aria-labelledby=\"nav-tools-tab\">\ | ||||
|  |         <div class=\"container my-5\" id=\"importNvs\">\ | ||||
|  |             <h2>NVS-Importer</h2>\ | ||||
|  |             <form action=\"/upload\" enctype=\"multipart/form-data\" method=\"POST\">\ | ||||
|  |                 <div class=\"form-group\">\ | ||||
|  |                     <label for=\"nvsUpload\">Hier kann eine Backup-Datei importiert werden.</label>\ | ||||
|  |                     <input type=\"file\" class=\"form-control-file\" id=\"nvsUpload\" name=\"nvsUpload\" accept=\".txt\">\ | ||||
|  |                 </div>\ | ||||
|  |                 <br>\ | ||||
|  |                 <div class=\"text-center\">\ | ||||
|  |                 <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ | ||||
|  |                 </div>\ | ||||
|  |             </form>\ | ||||
|  |         </div>\ | ||||
|  |     </div>\ | ||||
|  | </div>\ | ||||
|  | <script type=\"text/javascript\">\ | ||||
|  |     var DEBUG = false;\ | ||||
|  |     var lastIdclicked = '';\ | ||||
|  |     var host = $(location).attr('hostname');\ | ||||
|  | \ | ||||
|  |     if (DEBUG) {\ | ||||
|  |         host = \"192.168.178.114\";\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     toastr.options = {\ | ||||
|  |         \"closeButton\": false,\ | ||||
|  |         \"debug\": false,\ | ||||
|  |         \"newestOnTop\": false,\ | ||||
|  |         \"progressBar\": false,\ | ||||
|  |         \"positionClass\": \"toast-top-right\",\ | ||||
|  |         \"preventDuplicates\": false,\ | ||||
|  |         \"onclick\": null,\ | ||||
|  |         \"showDuration\": \"300\",\ | ||||
|  |         \"hideDuration\": \"1000\",\ | ||||
|  |         \"timeOut\": \"5000\",\ | ||||
|  |         \"extendedTimeOut\": \"1000\",\ | ||||
|  |         \"showEasing\": \"swing\",\ | ||||
|  |         \"hideEasing\": \"linear\",\ | ||||
|  |         \"showMethod\": \"fadeIn\",\ | ||||
|  |         \"hideMethod\": \"fadeOut\"\ | ||||
|  |     };\ | ||||
|  | \ | ||||
|  |     function postRendering(event, data) {\ | ||||
|  |         Object.keys(data.instance._model.data).forEach(function (key, index) {\ | ||||
|  | \ | ||||
|  |             var cur = data.instance.get_node(data.instance._model.data[key]);\ | ||||
|  |             var lastFolder = cur['id'].split('/').filter(function (el) {\ | ||||
|  |                 return el.trim().length > 0;\ | ||||
|  |             }).pop();\ | ||||
|  |             if ((/\\.(mp3|MP3|ogg|wav|WAV|OGG|wma|WMA|acc|ACC|flac|FLAC)$/i).test(lastFolder)) {\ | ||||
|  |                 data.instance.set_type(data.instance._model.data[key], 'audio');\ | ||||
|  |             } else {\ | ||||
|  |                 if (data.instance._model.data[key]['type'] == \"file\") {\ | ||||
|  |                     data.instance.disable_node(data.instance._model.data[key]);\ | ||||
|  |                 }\ | ||||
|  |             }\ | ||||
|  |             data.instance.rename_node(data.instance._model.data[key], lastFolder);\ | ||||
|  |         });\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function renderFileTree() {\ | ||||
|  | \ | ||||
|  |         var filesURI = \"/files\";\ | ||||
|  |         if (DEBUG) {\ | ||||
|  |             filesURI = \"http://\" + host + \"/files\";\ | ||||
|  |         }\ | ||||
|  |         $('#filetree').jstree({\ | ||||
|  |             'core': {\ | ||||
|  |                 'check_callback': true,\ | ||||
|  |                 'data': {\ | ||||
|  |                     url: filesURI,\ | ||||
|  |                     error: function (XMLHttpRequest, textStatus, errorThrown) {\ | ||||
|  |                         $('#j1_loading').hide();\ | ||||
|  |                         $(\"#refreshAction\").hide();\ | ||||
|  |                         $('#filetree').html(\"<div class='clickForRefresh' ><i class='fas fa-sync fa-1x'><span id='#clickForRefresh' > Dateien suchen.</span></div>\");\ | ||||
|  |                         $('#filetree').on(\"click\", function () {\ | ||||
|  |                             refreshFileList();\ | ||||
|  |                         });\ | ||||
|  |                         toastr.error(\"Die Verzeichnis-Liste konnte nicht geladen werden.\");\ | ||||
|  |                     }\ | ||||
|  |                 },\ | ||||
|  | \ | ||||
|  |             },\ | ||||
|  |             'types': {\ | ||||
|  |                 'folder': {\ | ||||
|  |                     'icon': \"fa fa-folder\"\ | ||||
|  |                 },\ | ||||
|  |                 'file': {\ | ||||
|  |                     'icon': \"fa fa-file\"\ | ||||
|  |                 },\ | ||||
|  |                 'audio': {\ | ||||
|  |                     'icon': \"fa fa-file-audio\"\ | ||||
|  |                 },\ | ||||
|  |                 'default': {\ | ||||
|  |                     'icon': \"fa fa-folder\"\ | ||||
|  |                 }\ | ||||
|  |             },\ | ||||
|  |             'plugins': [\"themes\", \"types\"]\ | ||||
|  |         }).bind('loaded.jstree', function (event, data) {\ | ||||
|  |             postRendering(event, data);\ | ||||
|  |             if ((data.instance._model.data['#']['children'].length == 0)) {\ | ||||
|  |                 toastr.info(\"Der SD-Karten-Index muss erzeugt werden.\");\ | ||||
|  |             }\ | ||||
|  |         }).bind('refresh.jstree', function (event, data) {\ | ||||
|  |             postRendering(event, data);\ | ||||
|  |         });\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     $('#filetree').on('select_node.jstree', function (e, data) {\ | ||||
|  |         $('input[name=fileOrUrl]').val(data.node.id);\ | ||||
|  | \ | ||||
|  |         if (data.node.type == \"folder\") {\ | ||||
|  |             $('.option-folder').show();\ | ||||
|  |             $('.option-file').hide();\ | ||||
|  |             $('#playMode option').removeAttr('selected').filter('[value=3]').attr('selected', true);\ | ||||
|  |         }\ | ||||
|  | \ | ||||
|  |         if (data.node.type == \"audio\") {\ | ||||
|  |             $('.option-file').show();\ | ||||
|  |             $('.option-folder').hide();\ | ||||
|  |             $('#playMode option').removeAttr('selected').filter('[value=1]').attr('selected', true);\ | ||||
|  |         }\ | ||||
|  |     });\ | ||||
|  | \ | ||||
|  |     $('#refreshAction').on(\"click\", function () {\ | ||||
|  |         refreshFileList();\ | ||||
|  |         $(\"#indexing-progress\").show();\ | ||||
|  |         $(\"#refreshAction\").hide();\ | ||||
|  |     });\ | ||||
|  | \ | ||||
|  |     $('#playMode').on(\"change\", function () {\ | ||||
|  |         if (this.value == 8) {\ | ||||
|  |             $('#filebrowser').slideUp();\ | ||||
|  |         } else {\ | ||||
|  |             $('#filebrowser').slideDown();\ | ||||
|  |         }\ | ||||
|  |     });\ | ||||
|  | \ | ||||
|  |     function showFileIndexingState() {\ | ||||
|  |         $(\"#indexing-progress\").show();\ | ||||
|  |         $(\"#refreshAction\").hide();\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function hideFileIndexingState() {\ | ||||
|  |         $(\"#indexing-progress\").hide();\ | ||||
|  |         $(\"#refreshAction\").show();\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     var socket = undefined;\ | ||||
|  |     var tm;\ | ||||
|  | \ | ||||
|  |     function connect() {\ | ||||
|  |         socket = new WebSocket(\"ws://\" + host + \"/ws\");\ | ||||
|  | \ | ||||
|  |         socket.onopen = function () {\ | ||||
|  |             setInterval(ping, 15000);\ | ||||
|  |         };\ | ||||
|  | \ | ||||
|  |         socket.onclose = function (e) {\ | ||||
|  |             console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);\ | ||||
|  |             socket = null;\ | ||||
|  |             setTimeout(function () {\ | ||||
|  |                 connect();\ | ||||
|  |             }, 5000);\ | ||||
|  |         };\ | ||||
|  | \ | ||||
|  |         socket.onerror = function (err) {\ | ||||
|  |             console.error('Socket encountered error: ', err.message, 'Closing socket');\ | ||||
|  |         };\ | ||||
|  | \ | ||||
|  |         socket.onmessage = function(event) {\ | ||||
|  |           console.log(event.data);\ | ||||
|  |           var socketMsg = JSON.parse(event.data);\ | ||||
|  |           if (socketMsg.rfidId != null) {\ | ||||
|  |               document.getElementById('rfidIdMod').value = socketMsg.rfidId;\ | ||||
|  |               document.getElementById('rfidIdMusic').value = socketMsg.rfidId;\ | ||||
|  |               toastr.info(\"RFID Tag mit \"+ socketMsg.rfidId + \" erkannt.\" );\ | ||||
|  | \ | ||||
|  |               $(\"#rfidIdMusic\").effect(\"highlight\", {color:\"#abf5af\"}, 3000);\ | ||||
|  |               $(\"#rfidIdMod\").effect(\"highlight\", {color:\"#abf5af\"}, 3000);\ | ||||
|  | \ | ||||
|  |           } if (\"status\" in socketMsg) {\ | ||||
|  |               if (socketMsg.status == \"ok\") {\ | ||||
|  |                   toastr.success(\"Aktion erfolgreich ausgeführt.\" );\ | ||||
|  |               }\ | ||||
|  |           } if (\"pong\" in socketMsg) {\ | ||||
|  |               if (socketMsg.pong == 'pong') {\ | ||||
|  |                   pong();\ | ||||
|  |               }\ | ||||
|  |           } if (\"refreshFileList\" in socketMsg) {\ | ||||
|  |               hideFileIndexingState();\ | ||||
|  |               toastr.info(\"Die Dateiliste wurde neu erzeugt!\");\ | ||||
|  |               $('#filetree').jstree(true).refresh();\ | ||||
|  | \ | ||||
|  |           }\ | ||||
|  |           if (\"indexingState\" in socketMsg) {\ | ||||
|  |               if(socketMsg.indexingState != null) {\ | ||||
|  |                   $(\"#currentProcessedFile\").text(socketMsg.indexingState);\ | ||||
|  |                   console.log(socketMsg.indexingState);\ | ||||
|  |               }\ | ||||
|  |           }\ | ||||
|  |       };\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function ping() {\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"ping\": {\ | ||||
|  |                 ping: 'ping'\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |         tm = setTimeout(function () {\ | ||||
|  |             toastr.warning('Die Verbindung zum Tonuino ist unterbrochen! Bitte Seite neu laden.');\ | ||||
|  |         }, 5000);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function pong() {\ | ||||
|  |         clearTimeout(tm);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function refreshFileList(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"refreshFileList\": true\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         $(\"#refreshAction\").hide();\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |         showFileIndexingState();\ | ||||
|  |     };\ | ||||
|  | \ | ||||
|  |     function genSettings(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"general\": {\ | ||||
|  |                 iVol: document.getElementById('initialVolume').value,\ | ||||
|  |                 mVolSpeaker: document.getElementById('maxVolumeSpeaker').value,\ | ||||
|  |                 mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\ | ||||
|  |                 iBright: document.getElementById('initBrightness').value,\ | ||||
|  |                 nBright: document.getElementById('nightBrightness').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);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function ftpSettings(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"ftp\": {\ | ||||
|  |                 ftpUser: document.getElementById('ftpUser').value,\ | ||||
|  |                 ftpPwd: document.getElementById('ftpPwd').value\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function mqttSettings(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var val;\ | ||||
|  |         if (document.getElementById('mqttEnable').checked) {\ | ||||
|  |             val = document.getElementById('mqttEnable').value;\ | ||||
|  |         } else {\ | ||||
|  |             val = 0;\ | ||||
|  |         }\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"mqtt\": {\ | ||||
|  |                 mqttEnable: val,\ | ||||
|  |                 mqttServer: document.getElementById('mqttServer').value,\ | ||||
|  |                 mqttUser: document.getElementById('mqttUser').value,\ | ||||
|  |                 mqttPwd: document.getElementById('mqttPwd').value\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function rfidMods(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"rfidMod\": {\ | ||||
|  |                 rfidIdMod: document.getElementById('rfidIdMod').value,\ | ||||
|  |                 modId: document.getElementById('modId').value\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function removeTrSlash(str) {\ | ||||
|  |         if (str.substr(-1) === '/') {\ | ||||
|  |             return str.substr(0, str.length - 1);\ | ||||
|  |         }\ | ||||
|  |         return str;\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function rfidAssign(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"rfidAssign\": {\ | ||||
|  |                 rfidIdMusic: document.getElementById('rfidIdMusic').value,\ | ||||
|  |                 fileOrUrl: removeTrSlash(document.getElementById('fileOrUrl').value),\ | ||||
|  |                 playMode: document.getElementById('playMode').value\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     function wifiConfig(clickedId) {\ | ||||
|  |         lastIdclicked = clickedId;\ | ||||
|  |         var myObj = {\ | ||||
|  |             \"wifiConfig\": {\ | ||||
|  |                 ssid: document.getElementById('ssid').value,\ | ||||
|  |                 pwd: document.getElementById('pwd').value,\ | ||||
|  |                 hostname: document.getElementById('hostname').value\ | ||||
|  |             }\ | ||||
|  |         };\ | ||||
|  |         var myJSON = JSON.stringify(myObj);\ | ||||
|  |         socket.send(myJSON);\ | ||||
|  |     }\ | ||||
|  | \ | ||||
|  |     $(document).ready(function () {\ | ||||
|  |         connect();\ | ||||
|  |         renderFileTree();\ | ||||
|  | \ | ||||
|  |         console.log(parseInt(document.getElementById('warningLowVoltage').value));\ | ||||
|  |         $(function () {\ | ||||
|  |             $('[data-toggle=\"tooltip\"]').tooltip();\ | ||||
|  |         });\ | ||||
|  | \ | ||||
|  |     });\ | ||||
|  | </script>\ | ||||
|  | </body>\ | ||||
|  | </html>\ | ||||
|  | "; | ||||
| @ -1,4 +1,4 @@ | |||||
| static const char mgtWebsite[] PROGMEM = "<!DOCTYPE html>\ |  | ||||
|  | static const char management_HTML[] PROGMEM = "<!DOCTYPE html>\ | ||||
| <html lang=\"de\">\ | <html lang=\"de\">\ | ||||
|   <head>\ |   <head>\ | ||||
|     <title>ESPuino-configuration</title>\ |     <title>ESPuino-configuration</title>\ | ||||
| @ -1,640 +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/tonuino/css/bootstrap.min.css\">\ |  | ||||
|     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css\"/>\ |  | ||||
|     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css\"/>\ |  | ||||
|     <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css\"/>\ |  | ||||
|     <script src=\"https://ts-cs.de/tonuino/js/jquery.min.js\"></script>\ |  | ||||
|     <script src=\"https://code.jquery.com/ui/1.12.0/jquery-ui.min.js\"></script>\ |  | ||||
|     <script src=\"https://ts-cs.de/tonuino/js/popper.min.js\"></script>\ |  | ||||
|     <script src=\"https://ts-cs.de/tonuino/js/bootstrap.min.js\"></script>\ |  | ||||
|     <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js\"></script>\ |  | ||||
|     <script src=\"https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js\"></script>\ |  | ||||
|     <style type=\"text/css\">\ |  | ||||
|         .filetree {\ |  | ||||
|             border: 1px solid black;\ |  | ||||
|             height: 200px;\ |  | ||||
|             margin: 0em 0em 1em 0em;\ |  | ||||
|             overflow-y: scroll;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .fa-sync:hover {\ |  | ||||
|             color: #666666;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .clickForRefresh {\ |  | ||||
|             text-align: center;\ |  | ||||
|             color: gray;\ |  | ||||
|             cursor: pointer;\ |  | ||||
|             margin-top: 5em;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .clickForRefresh:hover {\ |  | ||||
|             color: darkgray;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .filetree-container {\ |  | ||||
|             position: relative;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .indexing-progress {\ |  | ||||
|             width: 100%%;\ |  | ||||
|             height: 100%%;\ |  | ||||
|             position: absolute;\ |  | ||||
|             top: 0;\ |  | ||||
|             left: 0;\ |  | ||||
|             opacity: 0.7;\ |  | ||||
|             display: none;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .refreshAction{\ |  | ||||
|             text-align: right;\ |  | ||||
|             font-size: 0.8em;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .refreshAction:hover{\ |  | ||||
|             cursor: pointer;\ |  | ||||
|             color: darkgray;\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         .overlay {\ |  | ||||
|             z-index: 9;\ |  | ||||
|             opacity: 0.8;\ |  | ||||
|             background: #1a1919;\ |  | ||||
|             height: 200px;\ |  | ||||
|             display: none;\ |  | ||||
|             width: 100%%;\ |  | ||||
|         }\ |  | ||||
|     </style>\ |  | ||||
| </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=\"https://raw.githubusercontent.com/biologist79/Tonuino-ESP32-I2S/master/html/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>\ |  | ||||
|             <li class=\"nav-item\">\ |  | ||||
|                 <a class=\"nav-link\" href=\"#importNvs\">NVS-Importer</a>\ |  | ||||
|             </li>\ |  | ||||
|             <li class=\"nav-item\">\ |  | ||||
|                 <a class=\"nav-link\" href=\"/restart\" style=\"color: orange\">Neustart Tonuino</a>\ |  | ||||
|             </li>\ |  | ||||
|         </ul>\ |  | ||||
|     </div>\ |  | ||||
| </nav>\ |  | ||||
| <br/>\ |  | ||||
| <div class=\"container\" id=\"wifiConfig\">\ |  | ||||
|     <h2>WLAN-Konfiguration</h2>\ |  | ||||
|     <form action=\"#wifiConfig\" method=\"POST\" onsubmit=\"wifiConfig('wifiConfig'); return false\">\ |  | ||||
|         <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>\ |  | ||||
|             <label for=\"hostname\">Tonuino-Name (Hostname):</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"hostname\" placeholder=\"tonuino\" name=\"hostname\"\ |  | ||||
|                    value=\"%HOSTNAME%\" pattern=\"^[^-\\.]{2,32}\" required>\ |  | ||||
|         </div>\ |  | ||||
|         <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |  | ||||
|         <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container my-5\" id=\"rfidMusicTags\">\ |  | ||||
|     <h2>RFID-Zuweisungen</h2>\ |  | ||||
|     <form action=\"#rfidMusicTags\" method=\"POST\" onsubmit=\"rfidAssign('rfidMusicTags'); return false\">\ |  | ||||
|         <div class=\"form-group col-md-6\">\ |  | ||||
|             <label for=\"rfidIdMusic\">RFID-Chip-Nummer (12-stellig)</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"rfidIdMusic\" maxlength=\"12\" pattern=\"[0-9]{12}\"\ |  | ||||
|                    placeholder=\"%RFID_TAG_ID%\" name=\"rfidIdMusic\" required>\ |  | ||||
|             <label for=\"fileOrUrl\">Datei, Verzeichnis oder URL (^ und # als Zeichen nicht erlaubt)</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"fileOrUrl\" maxlength=\"255\" placeholder=\"z.B. /mp3/Hoerspiele/Yakari/Yakari_und_seine_Freunde.mp3\" pattern=\"^[^\\^#]+$\" name=\"fileOrUrl\" required>\ |  | ||||
|             <div class=\"filetree-container\">\ |  | ||||
|                 <div id=\"filebrowser\">\ |  | ||||
|                     <div class=\"filetree demo\" id=\"filetree\"></div>\ |  | ||||
|                     <div class=\"refreshAction\">\ |  | ||||
|                         <span id=\"refreshAction\" data-toggle=\"tooltip\" data-placement=\"top\" title=\"Datei Liste aktualisieren.\"><i class=\"fas fa-sync fa-1x\"></i> Dateiliste aktualisieren</span>\ |  | ||||
|                     </div>\ |  | ||||
|                 </div>\ |  | ||||
|                 <div id=\"indexing-progress\" class=\"indexing-progress overlay\">\ |  | ||||
|                     <div style=\"text-align: center; color:white; margin-top:2em;\">\ |  | ||||
|                         <div><i class=\"fas fa-sync fa-spin fa-2x\"></i> <br><br>  Der Prozess kann mehrere Minuten dauern...</div>\ |  | ||||
|                         <div id=\"currentProcessedFile\"></div>\ |  | ||||
|                     </div>\ |  | ||||
|                 </div>\ |  | ||||
|             </div>\ |  | ||||
|             <label for=\"playMode\">Abspielmodus</label>\ |  | ||||
|             <select class=\"form-control\" id=\"playMode\" name=\"playMode\">\ |  | ||||
|                 <option class=\"option-file\" value=\"1\">Einzelner Titel</option>\ |  | ||||
|                 <option class=\"option-file\" value=\"2\">Einzelner Titel (Endlosschleife)</option>\ |  | ||||
|                 <option class=\"option-file-and-folder\" value=\"3\">Hörbuch</option>\ |  | ||||
|                 <option class=\"option-file-and-folder\" value=\"4\">Hörbuch (Endlosschleife)</option>\ |  | ||||
|                 <option class=\"option-folder\" value=\"5\">Alle Titel eines Verzeichnis (sortiert)</option>\ |  | ||||
|                 <option class=\"option-folder\" value=\"6\">Alle Titel eines Verzeichnis (zufällig)</option>\ |  | ||||
|                 <option class=\"option-folder\" value=\"7\">Alle Titel eines Verzeichnis (sortiert, Endlosschleife)</option>\ |  | ||||
|                 <option class=\"option-folder\" value=\"9\">Alle Titel eines Verzeichnis (zufällig, Endlosschleife)</option>\ |  | ||||
|                 <option class=\"option-stream\" value=\"8\">Webradio</option>\ |  | ||||
|             </select>\ |  | ||||
|         </div>\ |  | ||||
|         <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |  | ||||
|         <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container my-5\" id=\"rfidModTags\">\ |  | ||||
|     <h2>RFID-Modifkationen</h2>\ |  | ||||
|     <form class=\"needs-validation\" action=\"#rfidModTags\" method=\"POST\" onsubmit=\"rfidMods('rfidModTags'); return false\">\ |  | ||||
|         <div class=\"form-group col-md-6\">\ |  | ||||
|             <label for=\"rfidIdMod\">RFID-Chip-Nummer (12-stellig)</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"rfidIdMod\" maxlength=\"12\" pattern=\"[0-9]{12}\"\ |  | ||||
|                    placeholder=\"%RFID_TAG_ID%\" 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=\"107\">Schlafen nach fünf Titeln</option>\ |  | ||||
|                 <option value=\"110\">Wiederhole Playlist (endlos)</option>\ |  | ||||
|                 <option value=\"111\">Wiederhole Titel (endlos)</option>\ |  | ||||
|                 <option value=\"112\">Dimme LEDs (Nachtmodus)</option>\ |  | ||||
|                 <option value=\"130\">Aktiviere/deaktive WLAN</option>\ |  | ||||
|             </select>\ |  | ||||
|         </div>\ |  | ||||
|         <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |  | ||||
|         <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container my-5\" id=\"mqttConfig\">\ |  | ||||
|     <h2>MQTT-Konfiguration</h2>\ |  | ||||
|     <form class=\"needs-validation\" action=\"#mqttConfig\" method=\"POST\"\ |  | ||||
|           onsubmit=\"mqttSettings('mqttConfig'); return false\">\ |  | ||||
|         <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</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"mqttServer\" minlength=\"7\" maxlength=\"%MQTT_SERVER_LENGTH%\"\ |  | ||||
|                    placeholder=\"z.B. 192.168.2.89\" name=\"mqttServer\" value=\"%MQTT_SERVER%\">\ |  | ||||
|             <label for=\"mqttUser\">MQTT-Benutzername (optional):</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"mqttUser\" maxlength=\"%MQTT_USER_LENGTH%\"\ |  | ||||
|                    placeholder=\"Benutzername\" name=\"mqttUser\" value=\"%MQTT_USER%\">\ |  | ||||
|             <label for=\"mqttPwd\">Passwort (optional):</label>\ |  | ||||
|             <input type=\"password\" class=\"form-control\" id=\"mqttPwd\" maxlength=\"%MQTT_PWD_LENGTH%\"\ |  | ||||
|                    placeholder=\"Passwort\" name=\"mqttPwd\" value=\"%MQTT_PWD%\">\ |  | ||||
|         </div>\ |  | ||||
|         <button type=\"reset\" class=\"btn btn-secondary\">Reset</button>\ |  | ||||
|         <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container\" id=\"ftpConfig\">\ |  | ||||
|     <h2>FTP-Konfiguration</h2>\ |  | ||||
|     <form action=\"#ftpConfig\" method=\"POST\" onsubmit=\"ftpSettings('ftpConfig'); return false\">\ |  | ||||
|         <div class=\"form-group col-md-6\">\ |  | ||||
|             <label for=\"ftpUser\">FTP-Benutzername:</label>\ |  | ||||
|             <input type=\"text\" class=\"form-control\" id=\"ftpUser\" maxlength=\"%FTP_USER_LENGTH%\"\ |  | ||||
|                    placeholder=\"Benutzername\" name=\"ftpUser\" value=\"%FTP_USER%\" required>\ |  | ||||
|             <label for=\"pwd\">Passwort:</label>\ |  | ||||
|             <input type=\"password\" class=\"form-control\" id=\"ftpPwd\" maxlength=\"%FTP_PWD_LENGTH%\" 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\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container my-5\" id=\"generalConfig\">\ |  | ||||
|     <h2>Allgemeine Konfiguration</h2>\ |  | ||||
|     <form action=\"#generalConfig\" method=\"POST\" onsubmit=\"genSettings('generalConfig'); return false\">\ |  | ||||
|         <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=\"maxVolumeSpeaker\">Maximale Lautstärke (Lautsprecher)</label>\ |  | ||||
|             <input type=\"number\" min=\"1\" max=\"21\" class=\"form-control\" id=\"maxVolumeSpeaker\" name=\"maxVolumeSpeaker\"\ |  | ||||
|                    value=\"%MAX_VOLUME_SPEAKER%\" required>\ |  | ||||
|             <label for=\"maxVolumeHeadphone\">Maximale Lautstärke (Kopfhörer)</label>\ |  | ||||
|             <input type=\"number\" min=\"1\" max=\"21\" class=\"form-control\" id=\"maxVolumeHeadphone\" name=\"maxVolumeHeadphone\"\ |  | ||||
|                    value=\"%MAX_VOLUME_HEADPHONE%\" 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_BRIGHTNESS%\" 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_BRIGHTNESS%\" 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>\ |  | ||||
|         <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=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <div class=\"container my-5\" id=\"importNvs\">\ |  | ||||
|     <h2>NVS-Importer</h2>\ |  | ||||
|     <form action=\"/upload\" enctype=\"multipart/form-data\" method=\"POST\">\ |  | ||||
|         <div class=\"form-group\">\ |  | ||||
|             <label for=\"nvsUpload\">Hier kann eine Backup-Datei importiert werden.</label>\ |  | ||||
|             <input type=\"file\" class=\"form-control-file\" id=\"nvsUpload\" name=\"nvsUpload\" accept=\".txt\">\ |  | ||||
|         </div>\ |  | ||||
|         <button type=\"submit\" class=\"btn btn-primary\">Absenden</button>\ |  | ||||
|     </form>\ |  | ||||
|     <div class=\"messages col-md-6 my-2\"></div>\ |  | ||||
| </div>\ |  | ||||
| <script type=\"text/javascript\">\ |  | ||||
|     var DEBUG = false;\ |  | ||||
|     var lastIdclicked = '';\ |  | ||||
|     var host = $(location).attr('hostname');\ |  | ||||
| \ |  | ||||
|     if (DEBUG) {\ |  | ||||
|         host = \"192.168.178.112\";\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     toastr.options = {\ |  | ||||
|         \"closeButton\": false,\ |  | ||||
|         \"debug\": false,\ |  | ||||
|         \"newestOnTop\": false,\ |  | ||||
|         \"progressBar\": false,\ |  | ||||
|         \"positionClass\": \"toast-top-right\",\ |  | ||||
|         \"preventDuplicates\": false,\ |  | ||||
|         \"onclick\": null,\ |  | ||||
|         \"showDuration\": \"300\",\ |  | ||||
|         \"hideDuration\": \"1000\",\ |  | ||||
|         \"timeOut\": \"5000\",\ |  | ||||
|         \"extendedTimeOut\": \"1000\",\ |  | ||||
|         \"showEasing\": \"swing\",\ |  | ||||
|         \"hideEasing\": \"linear\",\ |  | ||||
|         \"showMethod\": \"fadeIn\",\ |  | ||||
|         \"hideMethod\": \"fadeOut\"\ |  | ||||
|     };\ |  | ||||
| \ |  | ||||
|     function postRendering(event, data) {\ |  | ||||
|         Object.keys(data.instance._model.data).forEach(function (key, index) {\ |  | ||||
| \ |  | ||||
|             var cur = data.instance.get_node(data.instance._model.data[key]);\ |  | ||||
|             var lastFolder = cur['id'].split('/').filter(function (el) {\ |  | ||||
|                 return el.trim().length > 0;\ |  | ||||
|             }).pop();\ |  | ||||
|             if ((/\\.(mp3|MP3|ogg|wav|WAV|OGG|wma|WMA|acc|ACC|flac|FLAC)$/i).test(lastFolder)) {\ |  | ||||
|                 data.instance.set_type(data.instance._model.data[key], 'audio');\ |  | ||||
|             } else {\ |  | ||||
|                 if (data.instance._model.data[key]['type'] == \"file\") {\ |  | ||||
|                     data.instance.disable_node(data.instance._model.data[key]);\ |  | ||||
|                 }\ |  | ||||
|             }\ |  | ||||
|             data.instance.rename_node(data.instance._model.data[key], lastFolder);\ |  | ||||
|         });\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function renderFileTree() {\ |  | ||||
| \ |  | ||||
|         var filesURI = \"/files\";\ |  | ||||
|         if (DEBUG) {\ |  | ||||
|             filesURI = \"http://\" + host + \"/files\";\ |  | ||||
|         }\ |  | ||||
|         $('#filetree').jstree({\ |  | ||||
|             'core': {\ |  | ||||
|                 'check_callback': true,\ |  | ||||
|                 'data': {\ |  | ||||
|                     url: filesURI,\ |  | ||||
|                     error: function (XMLHttpRequest, textStatus, errorThrown) {\ |  | ||||
|                         $('#j1_loading').hide();\ |  | ||||
|                         $(\"#refreshAction\").hide();\ |  | ||||
|                         $('#filetree').html(\"<div class='clickForRefresh' ><i class='fas fa-sync fa-1x'><span id='#clickForRefresh' > Dateien suchen.</span></div>\");\ |  | ||||
|                         $('#filetree').on(\"click\", function () {\ |  | ||||
|                             refreshFileList();\ |  | ||||
|                         });\ |  | ||||
|                         toastr.error(\"Die Verzeichnis-Liste konnte nicht geladen werden.\");\ |  | ||||
|                     }\ |  | ||||
|                 },\ |  | ||||
| \ |  | ||||
|             },\ |  | ||||
|             'types': {\ |  | ||||
|                 'folder': {\ |  | ||||
|                     'icon': \"fa fa-folder\"\ |  | ||||
|                 },\ |  | ||||
|                 'file': {\ |  | ||||
|                     'icon': \"fa fa-file\"\ |  | ||||
|                 },\ |  | ||||
|                 'audio': {\ |  | ||||
|                     'icon': \"fa fa-file-audio\"\ |  | ||||
|                 },\ |  | ||||
|                 'default': {\ |  | ||||
|                     'icon': \"fa fa-folder\"\ |  | ||||
|                 }\ |  | ||||
|             },\ |  | ||||
|             'plugins': [\"themes\", \"types\"]\ |  | ||||
|         }).bind('loaded.jstree', function (event, data) {\ |  | ||||
|             postRendering(event, data);\ |  | ||||
|             if ((data.instance._model.data['#']['children'].length == 0)) {\ |  | ||||
|                 toastr.info(\"Der SD-Karten-Index muss erzeugt werden.\");\ |  | ||||
|             }\ |  | ||||
|         }).bind('refresh.jstree', function (event, data) {\ |  | ||||
|             postRendering(event, data);\ |  | ||||
|         });\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     $('#filetree').on('select_node.jstree', function (e, data) {\ |  | ||||
|         $('input[name=fileOrUrl]').val(data.node.id);\ |  | ||||
| \ |  | ||||
|         if (data.node.type == \"folder\") {\ |  | ||||
|             $('.option-folder').show();\ |  | ||||
|             $('.option-file').hide();\ |  | ||||
|             $('#playMode option').removeAttr('selected').filter('[value=3]').attr('selected', true);\ |  | ||||
|         }\ |  | ||||
| \ |  | ||||
|         if (data.node.type == \"audio\") {\ |  | ||||
|             $('.option-file').show();\ |  | ||||
|             $('.option-folder').hide();\ |  | ||||
|             $('#playMode option').removeAttr('selected').filter('[value=1]').attr('selected', true);\ |  | ||||
|         }\ |  | ||||
|     });\ |  | ||||
| \ |  | ||||
|     $('#refreshAction').on(\"click\", function () {\ |  | ||||
|         refreshFileList();\ |  | ||||
|         $(\"#indexing-progress\").show();\ |  | ||||
|         $(\"#refreshAction\").hide();\ |  | ||||
|     });\ |  | ||||
| \ |  | ||||
|     $('#playMode').on(\"change\", function () {\ |  | ||||
|         if (this.value == 8) {\ |  | ||||
|             $('#filebrowser').slideUp();\ |  | ||||
|         } else {\ |  | ||||
|             $('#filebrowser').slideDown();\ |  | ||||
|         }\ |  | ||||
|     });\ |  | ||||
| \ |  | ||||
|     function showFileIndexingState() {\ |  | ||||
|         $(\"#indexing-progress\").show();\ |  | ||||
|         $(\"#refreshAction\").hide();\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function hideFileIndexingState() {\ |  | ||||
|         $(\"#indexing-progress\").hide();\ |  | ||||
|         $(\"#refreshAction\").show();\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     var socket = undefined;\ |  | ||||
|     var tm;\ |  | ||||
| \ |  | ||||
|     function connect() {\ |  | ||||
|         socket = new WebSocket(\"ws://\" + host + \"/ws\");\ |  | ||||
| \ |  | ||||
|         socket.onopen = function () {\ |  | ||||
|             setInterval(ping, 15000);\ |  | ||||
|         };\ |  | ||||
| \ |  | ||||
|         socket.onclose = function (e) {\ |  | ||||
|             console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);\ |  | ||||
|             socket = null;\ |  | ||||
|             setTimeout(function () {\ |  | ||||
|                 connect();\ |  | ||||
|             }, 5000);\ |  | ||||
|         };\ |  | ||||
| \ |  | ||||
|         socket.onerror = function (err) {\ |  | ||||
|             console.error('Socket encountered error: ', err.message, 'Closing socket');\ |  | ||||
|         };\ |  | ||||
| \ |  | ||||
|         socket.onmessage = function(event) {\ |  | ||||
|           console.log(event.data);\ |  | ||||
|           var socketMsg = JSON.parse(event.data);\ |  | ||||
|           if (socketMsg.rfidId != null) {\ |  | ||||
|               document.getElementById('rfidIdMod').value = socketMsg.rfidId;\ |  | ||||
|               document.getElementById('rfidIdMusic').value = socketMsg.rfidId;\ |  | ||||
|               toastr.info(\"RFID Tag mit \"+ socketMsg.rfidId + \" erkannt.\" );\ |  | ||||
| \ |  | ||||
|               $(\"#rfidIdMusic\").effect(\"highlight\", {color:\"#abf5af\"}, 3000);\ |  | ||||
|               $(\"#rfidIdMod\").effect(\"highlight\", {color:\"#abf5af\"}, 3000);\ |  | ||||
| \ |  | ||||
|           } if (\"status\" in socketMsg) {\ |  | ||||
|               if (socketMsg.status == \"ok\") {\ |  | ||||
|                   toastr.success(\"Aktion erfolgreich ausgeführt.\" );\ |  | ||||
|               }\ |  | ||||
|           } if (\"pong\" in socketMsg) {\ |  | ||||
|               if (socketMsg.pong == 'pong') {\ |  | ||||
|                   pong();\ |  | ||||
|               }\ |  | ||||
|           } if (\"refreshFileList\" in socketMsg) {\ |  | ||||
|               hideFileIndexingState();\ |  | ||||
|               toastr.info(\"Die Dateiliste wurde neu erzeugt!\");\ |  | ||||
|               $('#filetree').jstree(true).refresh();\ |  | ||||
| \ |  | ||||
|           }\ |  | ||||
|           if (\"indexingState\" in socketMsg) {\ |  | ||||
|               if(socketMsg.indexingState != null) {\ |  | ||||
|                   $(\"#currentProcessedFile\").text(socketMsg.indexingState);\ |  | ||||
|                   console.log(socketMsg.indexingState);\ |  | ||||
|               }\ |  | ||||
|           }\ |  | ||||
|       };\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function ping() {\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"ping\": {\ |  | ||||
|                 ping: 'ping'\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|         tm = setTimeout(function () {\ |  | ||||
|             toastr.warning('Die Verbindung zum Tonuino ist unterbrochen! Bitte Seite neu laden.');\ |  | ||||
|         }, 5000);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function pong() {\ |  | ||||
|         clearTimeout(tm);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function refreshFileList(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"refreshFileList\": true\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         $(\"#refreshAction\").hide();\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|         showFileIndexingState();\ |  | ||||
|     };\ |  | ||||
| \ |  | ||||
|     function genSettings(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"general\": {\ |  | ||||
|                 iVol: document.getElementById('initialVolume').value,\ |  | ||||
|                 mVolSpeaker: document.getElementById('maxVolumeSpeaker').value,\ |  | ||||
|                 mVolHeadphone: document.getElementById('maxVolumeHeadphone').value,\ |  | ||||
|                 iBright: document.getElementById('initBrightness').value,\ |  | ||||
|                 nBright: document.getElementById('nightBrightness').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);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function ftpSettings(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"ftp\": {\ |  | ||||
|                 ftpUser: document.getElementById('ftpUser').value,\ |  | ||||
|                 ftpPwd: document.getElementById('ftpPwd').value\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function mqttSettings(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var val;\ |  | ||||
|         if (document.getElementById('mqttEnable').checked) {\ |  | ||||
|             val = document.getElementById('mqttEnable').value;\ |  | ||||
|         } else {\ |  | ||||
|             val = 0;\ |  | ||||
|         }\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"mqtt\": {\ |  | ||||
|                 mqttEnable: val,\ |  | ||||
|                 mqttServer: document.getElementById('mqttServer').value,\ |  | ||||
|                 mqttUser: document.getElementById('mqttUser').value,\ |  | ||||
|                 mqttPwd: document.getElementById('mqttPwd').value\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function rfidMods(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"rfidMod\": {\ |  | ||||
|                 rfidIdMod: document.getElementById('rfidIdMod').value,\ |  | ||||
|                 modId: document.getElementById('modId').value\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function removeTrSlash(str) {\ |  | ||||
|         if (str.substr(-1) === '/') {\ |  | ||||
|             return str.substr(0, str.length - 1);\ |  | ||||
|         }\ |  | ||||
|         return str;\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function rfidAssign(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"rfidAssign\": {\ |  | ||||
|                 rfidIdMusic: document.getElementById('rfidIdMusic').value,\ |  | ||||
|                 fileOrUrl: removeTrSlash(document.getElementById('fileOrUrl').value),\ |  | ||||
|                 playMode: document.getElementById('playMode').value\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     function wifiConfig(clickedId) {\ |  | ||||
|         lastIdclicked = clickedId;\ |  | ||||
|         var myObj = {\ |  | ||||
|             \"wifiConfig\": {\ |  | ||||
|                 ssid: document.getElementById('ssid').value,\ |  | ||||
|                 pwd: document.getElementById('pwd').value,\ |  | ||||
|                 hostname: document.getElementById('hostname').value\ |  | ||||
|             }\ |  | ||||
|         };\ |  | ||||
|         var myJSON = JSON.stringify(myObj);\ |  | ||||
|         socket.send(myJSON);\ |  | ||||
|     }\ |  | ||||
| \ |  | ||||
|     $(document).ready(function () {\ |  | ||||
|         connect();\ |  | ||||
|         renderFileTree();\ |  | ||||
| \ |  | ||||
|         $(function () {\ |  | ||||
|             $('[data-toggle=\"tooltip\"]').tooltip();\ |  | ||||
|         });\ |  | ||||
|     });\ |  | ||||
| </script>\ |  | ||||
| </body>\ |  | ||||
| </html>\ |  | ||||
| "; |  | ||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue