mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Add TCP console for remote management via telnet/netcat
This commit is contained in:
parent
e97d6849d2
commit
d4d98ebbbe
6 changed files with 200 additions and 10 deletions
|
|
@ -2,6 +2,11 @@
|
|||
#include <Mesh.h>
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(ADMIN_PASSWORD, ADVERT_NAME);
|
||||
#endif
|
||||
|
||||
// Believe it or not, this std C function is busted on some platforms!
|
||||
static uint32_t _atoi(const char* sp) {
|
||||
uint32_t n = 0;
|
||||
|
|
@ -109,6 +114,10 @@ void setup() {
|
|||
Serial.begin(115200);
|
||||
|
||||
board.begin();
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
DisplayDriver* disp = NULL;
|
||||
|
|
@ -227,9 +236,14 @@ void setup() {
|
|||
|
||||
void loop() {
|
||||
the_mesh.loop();
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
|
||||
rtc_clock.tick();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(ADMIN_PASSWORD, ADVERT_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include "UITask.h"
|
||||
static UITask ui_task(display);
|
||||
|
|
@ -34,6 +39,10 @@ void setup() {
|
|||
|
||||
board.begin();
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#if defined(MESH_DEBUG) && defined(NRF52_PLATFORM)
|
||||
// give some extra time for serial to settle so
|
||||
// boot debug messages can be seen on terminal
|
||||
|
|
@ -148,6 +157,10 @@ void loop() {
|
|||
#endif
|
||||
|
||||
the_mesh.loop();
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "MyMesh.h"
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
#include <helpers/esp32/TCPConsole.h>
|
||||
TCPConsole tcp_console(ADMIN_PASSWORD, ADVERT_NAME);
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include "UITask.h"
|
||||
static UITask ui_task(display);
|
||||
|
|
@ -24,6 +29,10 @@ void setup() {
|
|||
|
||||
board.begin();
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.begin();
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
if (display.begin()) {
|
||||
display.startFrame();
|
||||
|
|
@ -108,9 +117,13 @@ void loop() {
|
|||
}
|
||||
|
||||
the_mesh.loop();
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT)
|
||||
tcp_console.loop(the_mesh);
|
||||
#endif
|
||||
|
||||
sensors.loop();
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
#ifdef DISPLAY_CLASS
|
||||
ui_task.loop();
|
||||
#endif
|
||||
rtc_clock.tick();
|
||||
}
|
||||
|
|
|
|||
142
src/helpers/esp32/TCPConsole.h
Normal file
142
src/helpers/esp32/TCPConsole.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(ESP32) && defined(TCP_CONSOLE_PORT) && defined(ADMIN_PASSWORD)
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
|
||||
#ifndef TCP_CONSOLE_MAX_CLIENTS
|
||||
#define TCP_CONSOLE_MAX_CLIENTS 2
|
||||
#endif
|
||||
|
||||
#ifndef TCP_CONSOLE_TIMEOUT_MS
|
||||
#define TCP_CONSOLE_TIMEOUT_MS 300000 // 5 minutes inactivity timeout
|
||||
#endif
|
||||
|
||||
class TCPConsole {
|
||||
WiFiServer _server;
|
||||
WiFiClient _clients[TCP_CONSOLE_MAX_CLIENTS];
|
||||
bool _authenticated[TCP_CONSOLE_MAX_CLIENTS];
|
||||
unsigned long _last_active[TCP_CONSOLE_MAX_CLIENTS];
|
||||
char _cmd_buf[TCP_CONSOLE_MAX_CLIENTS][160];
|
||||
int _cmd_len[TCP_CONSOLE_MAX_CLIENTS];
|
||||
const char* _password;
|
||||
const char* _node_name;
|
||||
|
||||
void sendToClient(int i, const char* msg) {
|
||||
if (_clients[i] && _clients[i].connected()) {
|
||||
_clients[i].print(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectClient(int i) {
|
||||
_clients[i].stop();
|
||||
_authenticated[i] = false;
|
||||
_cmd_buf[i][0] = 0;
|
||||
_cmd_len[i] = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
TCPConsole(const char* password, const char* node_name)
|
||||
: _server(TCP_CONSOLE_PORT), _password(password), _node_name(node_name) {
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
_authenticated[i] = false;
|
||||
_cmd_buf[i][0] = 0;
|
||||
_cmd_len[i] = 0;
|
||||
_last_active[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void begin() {
|
||||
_server.begin();
|
||||
Serial.printf("TCP Console listening on port %d\n", TCP_CONSOLE_PORT);
|
||||
}
|
||||
|
||||
// Call this from loop(), passing the mesh's handleCommand function
|
||||
template<typename T>
|
||||
void loop(T& mesh) {
|
||||
// Accept new clients
|
||||
WiFiClient newClient = _server.available();
|
||||
if (newClient) {
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
if (!_clients[i] || !_clients[i].connected()) {
|
||||
_clients[i] = newClient;
|
||||
_authenticated[i] = false;
|
||||
_cmd_buf[i][0] = 0;
|
||||
_cmd_len[i] = 0;
|
||||
_last_active[i] = millis();
|
||||
sendToClient(i, "MeshCore Console\r\nPassword: ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle connected clients
|
||||
for (int i = 0; i < TCP_CONSOLE_MAX_CLIENTS; i++) {
|
||||
if (!_clients[i] || !_clients[i].connected()) continue;
|
||||
|
||||
// Inactivity timeout
|
||||
if (millis() - _last_active[i] > TCP_CONSOLE_TIMEOUT_MS) {
|
||||
sendToClient(i, "\r\nTimeout. Disconnecting.\r\n");
|
||||
disconnectClient(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read available data
|
||||
while (_clients[i].available()) {
|
||||
_last_active[i] = millis();
|
||||
char c = _clients[i].read();
|
||||
|
||||
if (c == '\n') continue; // ignore LF, handle CR only
|
||||
|
||||
if (c != '\r' && _cmd_len[i] < 158) {
|
||||
_cmd_buf[i][_cmd_len[i]++] = c;
|
||||
_cmd_buf[i][_cmd_len[i]] = 0;
|
||||
if (!_authenticated[i]) {
|
||||
sendToClient(i, "*"); // mask password input
|
||||
} else {
|
||||
_clients[i].print(c); // echo command
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Got CR — process command
|
||||
sendToClient(i, "\r\n");
|
||||
_cmd_buf[i][_cmd_len[i]] = 0;
|
||||
|
||||
if (!_authenticated[i]) {
|
||||
// Authentication
|
||||
if (strcmp(_cmd_buf[i], _password) == 0) {
|
||||
_authenticated[i] = true;
|
||||
char welcome[80];
|
||||
snprintf(welcome, sizeof(welcome), "Welcome to %s console.\r\n> ", _node_name);
|
||||
sendToClient(i, welcome);
|
||||
} else {
|
||||
sendToClient(i, "Wrong password. Disconnecting.\r\n");
|
||||
disconnectClient(i);
|
||||
}
|
||||
} else {
|
||||
// Execute command
|
||||
if (strlen(_cmd_buf[i]) > 0) {
|
||||
char reply[160];
|
||||
reply[0] = 0;
|
||||
mesh.handleCommand(0, _cmd_buf[i], reply);
|
||||
if (reply[0]) {
|
||||
sendToClient(i, " -> ");
|
||||
sendToClient(i, reply);
|
||||
sendToClient(i, "\r\n");
|
||||
}
|
||||
}
|
||||
sendToClient(i, "> ");
|
||||
}
|
||||
|
||||
_cmd_buf[i][0] = 0;
|
||||
_cmd_len[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ESP32 && TCP_CONSOLE_PORT
|
||||
|
|
@ -49,7 +49,7 @@ lib_deps =
|
|||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Repeater"'
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Repeater eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
|
|
@ -59,6 +59,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
|
|
@ -101,7 +102,7 @@ lib_deps =
|
|||
extends = LilyGo_T_ETH_Elite_SX1262
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1262.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Room"'
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1262 Room eth"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
|
|
@ -111,6 +112,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
|
|
@ -130,6 +132,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
|
|
@ -149,6 +152,7 @@ build_flags =
|
|||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D WIFI_SSID='"WIFI_SSID"'
|
||||
-D WIFI_PWD='"Password"'
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1262.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ lib_deps =
|
|||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Repeater"'
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Repeater eth"'
|
||||
-D ADVERT_LAT=0
|
||||
-D ADVERT_LON=0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
|
|
@ -58,6 +58,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_repeater>
|
||||
lib_deps =
|
||||
|
|
@ -100,7 +101,7 @@ lib_deps =
|
|||
extends = LilyGo_T_ETH_Elite_SX1276
|
||||
build_flags =
|
||||
${LilyGo_T_ETH_Elite_SX1276.build_flags}
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Room"'
|
||||
-D ADVERT_NAME='"T-ETH Elite SX1276 Room eth"'
|
||||
-D ADVERT_LAT=0.0
|
||||
-D ADVERT_LON=0.0
|
||||
-D ADMIN_PASSWORD='"password"'
|
||||
|
|
@ -110,6 +111,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<../examples/simple_room_server>
|
||||
lib_deps =
|
||||
|
|
@ -129,6 +131,7 @@ build_flags =
|
|||
-D ETH_GATEWAY=192,168,254,254
|
||||
-D ETH_SUBNET=255,255,255,0
|
||||
-D ETH_DNS=8,8,8,8
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
|
|
@ -148,6 +151,7 @@ build_flags =
|
|||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D WIFI_SSID='"WIFI_SSID"'
|
||||
-D WIFI_PWD='"Password"'
|
||||
-D TCP_CONSOLE_PORT=4242
|
||||
build_src_filter = ${LilyGo_T_ETH_Elite_SX1276.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
+<helpers/ui/MomentaryButton.cpp>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue