Skip to content

Commit 6ea4020

Browse files
fhirschmannclaude
andcommitted
feat: allow stopping the FTP server from the web interface
Add Ftp_DisableServer()/Ftp_IsServerRunning(), report the FTP state over the websocket (on connect and after start/stop requests) and turn the FTP start button into a red stop button while the server is running - matching the bluetooth mode buttons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f16030f commit 6ea4020

12 files changed

Lines changed: 64 additions & 7 deletions

File tree

‎html/locales/de.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@
326326
"start": {
327327
"title": "FTP-Server starten",
328328
"desc": "Aktiviert den FTP-Server bis zum Neustart des Geräts.",
329-
"button": "FTP-Server starten"
329+
"button": "FTP-Server starten",
330+
"stopButton": "FTP-Server stoppen"
330331
}
331332
},
332333
"bt": {

‎html/locales/en.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@
327327
"start": {
328328
"title": "Start FTP-server",
329329
"desc": "Enables FTP-server until device is restarted.",
330-
"button": "Start FTP-server"
330+
"button": "Start FTP-server",
331+
"stopButton": "Stop FTP server"
331332
}
332333
},
333334
"bt": {

‎html/locales/fr.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@
319319
"start": {
320320
"title": "Démarrer serveur FTP",
321321
"desc": "Active le serveur FTP jusqu'au redémarrage du périphérique.",
322-
"button": "Démarrer le serveur FTP"
322+
"button": "Démarrer le serveur FTP",
323+
"stopButton": "Arrêter le serveur FTP"
323324
}
324325
},
325326
"bt": {

‎html/management.html‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,7 +1605,7 @@ <h5 class="modal-title" data-i18n="tools.nvs.erase.title"></h5>
16051605
<div data-i18n="ftp.start.desc"></div>
16061606
<br>
16071607
<div class="text-center">
1608-
<button type="button" class="btn btn-primary" onclick="ftpStart()"
1608+
<button type="button" class="btn btn-primary" id="ftpModeBtn" onclick="ftpSetStatus(1)"
16091609
data-i18n="ftp.start.button"></button>
16101610
</div>
16111611
</div>
@@ -3180,6 +3180,9 @@ <h5 class="modal-title" data-i18n="tools.nvs.erase.title"></h5>
31803180
currentOpMode = socketMsg.opmode;
31813181
updateOperationModeIndicator(socketMsg.opmode);
31823182
}
3183+
if ("ftpStatus" in socketMsg) {
3184+
updateFtpButton(socketMsg.ftpStatus.running);
3185+
}
31833186
if ("volume" in socketMsg) {
31843187
volumeSlider.setValue(parseInt(socketMsg.volume));
31853188
}
@@ -3880,16 +3883,28 @@ <h5 class="modal-title" data-i18n="tools.nvs.erase.title"></h5>
38803883
toaster.info(i18next.t("toast.saved"));
38813884
}
38823885

3883-
function ftpStart() {
3886+
function ftpSetStatus(start) {
38843887
var myObj = {
38853888
"ftpStatus": {
3886-
start: 1
3889+
start: start
38873890
}
38883891
};
38893892
var myJSON = JSON.stringify(myObj);
38903893
socket.send(myJSON);
38913894
}
38923895

3896+
/* Turns the FTP start button into a stop button while the server is running */
3897+
function updateFtpButton(running) {
3898+
const btn = document.getElementById('ftpModeBtn');
3899+
btn.setAttribute('data-i18n', running ? 'ftp.start.stopButton' : 'ftp.start.button');
3900+
btn.onclick = () => ftpSetStatus(running ? 0 : 1);
3901+
btn.classList.toggle('btn-danger', running);
3902+
btn.classList.toggle('btn-primary', !running);
3903+
if (localize) {
3904+
localize('#ftpModeBtn');
3905+
}
3906+
}
3907+
38933908
async function mqttSettings(clickedId) {
38943909
lastIdclicked = clickedId;
38953910
var val;

‎src/Ftp.cpp‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ void Ftp_EnableServer(void) {
9595
}
9696
}
9797

98+
void Ftp_DisableServer(void) {
99+
#ifdef FTP_ENABLE
100+
if (ftpEnableLastStatus || ftpEnableCurrentStatus) {
101+
if (ftpSrv != NULL) {
102+
delete ftpSrv; // also closes the listening socket and all client connections
103+
ftpSrv = NULL;
104+
}
105+
ftpEnableLastStatus = false;
106+
ftpEnableCurrentStatus = false;
107+
Log_Println(ftpServerStopped, LOGLEVEL_NOTICE);
108+
System_IndicateOk();
109+
} else {
110+
System_IndicateError();
111+
}
112+
#endif
113+
}
114+
115+
bool Ftp_IsServerRunning(void) {
116+
#ifdef FTP_ENABLE
117+
return ftpEnableLastStatus;
118+
#else
119+
return false;
120+
#endif
121+
}
122+
98123
// Creates FTP-instance only when requested
99124
void ftpManager(void) {
100125
#ifdef FTP_ENABLE

‎src/Ftp.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ void Ftp_Init(void);
77
void Ftp_Exit(void);
88
void Ftp_Cyclic(void);
99
void Ftp_EnableServer(void);
10+
void Ftp_DisableServer(void);
11+
bool Ftp_IsServerRunning(void);

‎src/LogMessages_DE.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ const char trackPausedAtPos[] = "Titel pausiert bei Position: %u (%u)";
173173
const char freeHeapWithoutFtp[] = "Freier Heap-Speicher vor FTP-Instanzierung: %u";
174174
const char freeHeapWithFtp[] = "Freier Heap-Speicher nach FTP-Instanzierung: %u";
175175
const char ftpServerStarted[] = "FTP-Server gestartet";
176+
const char ftpServerStopped[] = "FTP-Server gestoppt";
176177
const char freeHeapAfterSetup[] = "Freier Heap-Speicher nach Setup-Routine";
177178
const char tryStaticIpConfig[] = "Statische IP-Konfiguration wird durchgeführt...";
178179
const char staticIPConfigFailed[] = "Statische IP-Konfiguration fehlgeschlagen";

‎src/LogMessages_EN.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ const char freeHeapWithoutFtp[] = "Free heap before FTP-allocation: %u";
175175
const char freeHeapWithFtp[] = "Free heap after FTP-allocation: %u";
176176
const char freeHeapAfterSetup[] = "Free heap after setup";
177177
const char ftpServerStarted[] = "FTP-Server started";
178+
const char ftpServerStopped[] = "FTP-Server stopped";
178179
const char tryStaticIpConfig[] = "Performing IP-configuration...";
179180
const char staticIPConfigFailed[] = "IP-configuration failed";
180181
const char wakeUpRfidNoCard[] = "Wakeup caused by low power card-detection. RF-field changed but no known card on reader was found. So I'll return back to sleep now...";

‎src/LogMessages_FR.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ const char freeHeapWithoutFtp[] = "Espace libre avant l'allocation FTP : %u";
173173
const char freeHeapWithFtp[] = "Espace libre après l'allocation FTP : %u";
174174
const char freeHeapAfterSetup[] = "Espace libre après la configuration";
175175
const char ftpServerStarted[] = "Serveur FTP démarré";
176+
const char ftpServerStopped[] = "Serveur FTP arrêté";
176177
const char tryStaticIpConfig[] = "Configuration IP statique en cours...";
177178
const char staticIPConfigFailed[] = "Échec de la configuration IP statique";
178179
const char wakeUpRfidNoCard[] = "Réveil causé par la détection de carte à faible puissance. Le champ RF a changé mais aucune carte connu sur le lecteur n'a été trouvée. Je vais donc retourner en mode veille maintenant...";

‎src/Web.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,10 @@ WebsocketCodeType JSONToSettings(JsonObject doc) {
872872
uint8_t _ftpStart = doc["ftpStatus"]["start"].as<uint8_t>();
873873
if (_ftpStart == 1) { // ifdef FTP_ENABLE is checked in Ftp_EnableServer()
874874
Ftp_EnableServer();
875+
} else {
876+
Ftp_DisableServer();
875877
}
878+
Web_SendWebsocketData(0, WebsocketCodeType::FtpStatus); // broadcast new status to all clients
876879
}
877880
if (doc["mqtt"].is<JsonObject>()) {
878881
uint8_t _mqttEnable = doc["mqtt"]["enable"].as<uint8_t>();
@@ -1613,6 +1616,9 @@ void Web_SendWebsocketData(uint32_t client, WebsocketCodeType code) {
16131616
object["bt_scan"] = "in_progress";
16141617
} else if (code == WebsocketCodeType::BluetoothScanComplete) {
16151618
object["bt_scan"] = "complete";
1619+
} else if (code == WebsocketCodeType::FtpStatus) {
1620+
JsonObject entry = object["ftpStatus"].to<JsonObject>();
1621+
entry["running"] = Ftp_IsServerRunning();
16161622
};
16171623

16181624
if (doc.overflowed()) {
@@ -1647,6 +1653,7 @@ void onWebsocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsE
16471653
Log_Printf(LOGLEVEL_DEBUG, "ws[%s][%u] connect", server->url(), client->id());
16481654
// Send initial operation mode and RSSI to newly connected client
16491655
Web_SendWebsocketData(client->id(), WebsocketCodeType::OperationMode);
1656+
Web_SendWebsocketData(client->id(), WebsocketCodeType::FtpStatus);
16501657
// client->printf("Hello Client %u :)", client->id());
16511658
// client->ping();
16521659
} else if (type == WS_EVT_DISCONNECT) {

0 commit comments

Comments
 (0)