Add print log functionality and device name handling
- Introduced functions to capture and manage incoming print logs. - Added a download link for the incoming print log in the web interface. - Updated device name prefix for BLE and added device name building logic. - Enhanced SerialCommand class with line handler support. - Implemented WiFi reconnect logic and status tracking.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr char kBleDeviceNamePrefix[] = "EggDuino_";
|
||||
constexpr char kBleDeviceNamePrefix[] = "EggBot_";
|
||||
constexpr char kBleServiceUuid[] = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
|
||||
constexpr char kBleRxCharUuid[] = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
|
||||
constexpr char kBleTxCharUuid[] = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
|
||||
@@ -30,18 +30,6 @@ void logBleDiag(const String &message)
|
||||
Log(message);
|
||||
}
|
||||
|
||||
void buildBleDeviceName(char *nameBuffer, size_t bufferSize)
|
||||
{
|
||||
if ((nameBuffer == NULL) || (bufferSize == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Tasmota-style chip ID uses the lower 24 bits of the ESP32 efuse MAC.
|
||||
const uint32_t chipId = static_cast<uint32_t>(ESP.getEfuseMac() & 0xFFFFFFULL);
|
||||
snprintf(nameBuffer, bufferSize, "%s%06X", kBleDeviceNamePrefix, chipId);
|
||||
}
|
||||
|
||||
bool queueBleByte(uint8_t value)
|
||||
{
|
||||
bool queued = false;
|
||||
@@ -112,7 +100,7 @@ class EggDuinoBleRxCallbacks : public NimBLECharacteristicCallbacks
|
||||
void startBleInterface()
|
||||
{
|
||||
char bleDeviceName[32] = {0};
|
||||
buildBleDeviceName(bleDeviceName, sizeof(bleDeviceName));
|
||||
buildDeviceName(bleDeviceName, sizeof(bleDeviceName));
|
||||
if (bleDeviceName[0] == '\0')
|
||||
{
|
||||
snprintf(bleDeviceName, sizeof(bleDeviceName), "%sUNKNOWN", kBleDeviceNamePrefix);
|
||||
|
||||
@@ -8,11 +8,15 @@ namespace
|
||||
const char *kConfigPath = "/config.json";
|
||||
const size_t kConfigJsonCapacity = 4096;
|
||||
const byte kDnsPort = 53;
|
||||
const unsigned long kWifiReconnectIntervalMs = 10000;
|
||||
|
||||
WebServer server(80);
|
||||
DNSServer dnsServer;
|
||||
bool configStoreReady = false;
|
||||
bool apModeActive = false;
|
||||
bool staReconnectEnabled = false;
|
||||
bool staConnectionKnown = false;
|
||||
unsigned long lastStaReconnectAttemptMs = 0;
|
||||
|
||||
void redirectToRoot()
|
||||
{
|
||||
@@ -82,6 +86,7 @@ button { margin-top: 18px; border: 0; background: #0b5ed7; color: white; padding
|
||||
#status { margin-top: 12px; min-height: 1.2em; }
|
||||
#log { margin-top: 20px; border: 1px solid #d6dfef; border-radius: 8px; background: #0f172a; color: #d2e3ff; padding: 10px; height: 220px; overflow-y: auto; white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 0.9rem; }
|
||||
#logTitle { margin-top: 24px; margin-bottom: 8px; font-weight: 700; }
|
||||
#downloadPrintLog { display: inline-block; margin-top: 8px; color: #0b5ed7; text-decoration: none; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -91,6 +96,7 @@ button { margin-top: 18px; border: 0; background: #0b5ed7; color: white; padding
|
||||
<button id="saveBtn" type="button">Speichern</button>
|
||||
<div id="status"></div>
|
||||
<div id="logTitle">Logs</div>
|
||||
<a id="downloadPrintLog" href="/api/print-log.txt" download="incoming-print-log.txt">Incoming print log herunterladen</a>
|
||||
<div id="log"></div>
|
||||
</main>
|
||||
<script>
|
||||
@@ -261,6 +267,15 @@ async function pollLogs() {
|
||||
server.send(200, "application/json", buildLogsJson(since));
|
||||
}
|
||||
|
||||
void handleDownloadPrintLog()
|
||||
{
|
||||
server.sendHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "0");
|
||||
server.sendHeader("Content-Disposition", "attachment; filename=\"incoming-print-log.txt\"");
|
||||
server.send(200, "text/plain; charset=utf-8", buildIncomingPrintLogText());
|
||||
}
|
||||
|
||||
void handleNotFound()
|
||||
{
|
||||
if (apModeActive)
|
||||
@@ -275,6 +290,44 @@ async function pollLogs() {
|
||||
}
|
||||
handleRoot();
|
||||
}
|
||||
|
||||
void handleWifiReconnect()
|
||||
{
|
||||
if (!staReconnectEnabled || apModeActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const wl_status_t wifiStatus = WiFi.status();
|
||||
if (wifiStatus == WL_CONNECTED)
|
||||
{
|
||||
if (!staConnectionKnown)
|
||||
{
|
||||
staConnectionKnown = true;
|
||||
Log(String("WLAN verbunden: ") + WiFi.localIP().toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (staConnectionKnown)
|
||||
{
|
||||
staConnectionKnown = false;
|
||||
Log("WLAN Verbindung verloren");
|
||||
}
|
||||
|
||||
const unsigned long now = millis();
|
||||
if (now - lastStaReconnectAttemptMs < kWifiReconnectIntervalMs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastStaReconnectAttemptMs = now;
|
||||
if (!WiFi.reconnect())
|
||||
{
|
||||
WiFi.begin(g_sWifiSsid.c_str(), g_sWifiPassword.c_str());
|
||||
}
|
||||
Log("WLAN Reconnect versucht");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ConfigParameter configParameters[] = {
|
||||
@@ -500,18 +553,23 @@ void startWebInterface()
|
||||
initConfigStore();
|
||||
bool staConnected = false;
|
||||
apModeActive = false;
|
||||
staReconnectEnabled = !g_sWifiSsid.isEmpty();
|
||||
staConnectionKnown = false;
|
||||
lastStaReconnectAttemptMs = millis();
|
||||
dnsServer.stop();
|
||||
String hostName = g_sHostname;
|
||||
hostName.trim();
|
||||
char deviceName[32] = {0};
|
||||
buildDeviceName(deviceName, sizeof(deviceName));
|
||||
String hostName = String(deviceName);
|
||||
if (hostName.isEmpty())
|
||||
{
|
||||
hostName = "EggDuino";
|
||||
hostName = "EggBot_UNKNOWN";
|
||||
}
|
||||
g_sHostname = hostName;
|
||||
|
||||
if (!g_sWifiSsid.isEmpty())
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.setHostname(hostName.c_str());
|
||||
WiFi.begin(g_sWifiSsid.c_str(), g_sWifiPassword.c_str());
|
||||
|
||||
@@ -523,6 +581,7 @@ void startWebInterface()
|
||||
delay(250);
|
||||
}
|
||||
staConnected = (WiFi.status() == WL_CONNECTED);
|
||||
staConnectionKnown = staConnected;
|
||||
if (staConnected)
|
||||
{
|
||||
Serial.println(String("http://") + WiFi.localIP().toString());
|
||||
@@ -536,6 +595,7 @@ void startWebInterface()
|
||||
server.on("/api/config", HTTP_GET, handleGetConfig);
|
||||
server.on("/api/config", HTTP_POST, handlePostConfig);
|
||||
server.on("/api/logs", HTTP_GET, handleGetLogs);
|
||||
server.on("/api/print-log.txt", HTTP_GET, handleDownloadPrintLog);
|
||||
server.onNotFound(handleNotFound);
|
||||
server.begin();
|
||||
startWifiProtocolInterface();
|
||||
@@ -546,11 +606,11 @@ void startWebInterface()
|
||||
#ifdef ESP32
|
||||
WiFi.softAPsetHostname(hostName.c_str());
|
||||
#endif
|
||||
if (WiFi.softAP("EggDuino"))
|
||||
if (WiFi.softAP(hostName.c_str()))
|
||||
{
|
||||
apModeActive = true;
|
||||
dnsServer.start(kDnsPort, "*", WiFi.softAPIP());
|
||||
Serial.println(String("AP aktiv: EggDuino / http://") + WiFi.softAPIP().toString() + " (Name: " + hostName + ")");
|
||||
Serial.println(String("AP aktiv: ") + hostName + " / http://" + WiFi.softAPIP().toString() + " (Name: " + hostName + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -562,6 +622,7 @@ void startWebInterface()
|
||||
server.on("/api/config", HTTP_GET, handleGetConfig);
|
||||
server.on("/api/config", HTTP_POST, handlePostConfig);
|
||||
server.on("/api/logs", HTTP_GET, handleGetLogs);
|
||||
server.on("/api/print-log.txt", HTTP_GET, handleDownloadPrintLog);
|
||||
server.on("/generate_204", HTTP_GET, redirectToRoot);
|
||||
server.on("/gen_204", HTTP_GET, redirectToRoot);
|
||||
server.on("/hotspot-detect.html", HTTP_GET, redirectToRoot);
|
||||
@@ -574,6 +635,8 @@ void startWebInterface()
|
||||
|
||||
void handleWebInterface()
|
||||
{
|
||||
handleWifiReconnect();
|
||||
|
||||
if (apModeActive)
|
||||
{
|
||||
dnsServer.processNextRequest();
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
#include "EggDuino.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool g_bPrintSessionActive = false;
|
||||
|
||||
void captureSerialProtocolLine(const char *line)
|
||||
{
|
||||
captureIncomingPrintLine(line, PROTOCOL_TRANSPORT_SERIAL);
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void captureBleProtocolLine(const char *line)
|
||||
{
|
||||
captureIncomingPrintLine(line, PROTOCOL_TRANSPORT_BLE);
|
||||
}
|
||||
|
||||
void captureWifiProtocolLine(const char *line)
|
||||
{
|
||||
captureIncomingPrintLine(line, PROTOCOL_TRANSPORT_WIFI);
|
||||
}
|
||||
#endif
|
||||
|
||||
void startPrintSessionIfNeeded()
|
||||
{
|
||||
if (!g_bPrintSessionActive)
|
||||
{
|
||||
clearIncomingPrintLog();
|
||||
g_bPrintSessionActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void stopPrintSession()
|
||||
{
|
||||
g_bPrintSessionActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void queryPen()
|
||||
{
|
||||
Log(__FUNCTION__);
|
||||
@@ -96,6 +132,8 @@ void stepperMove()
|
||||
sendAck();
|
||||
return;
|
||||
}
|
||||
|
||||
startPrintSessionIfNeeded();
|
||||
|
||||
prepareMove(duration, penStepsEBB, rotStepsEBB);
|
||||
moveToDestination();
|
||||
@@ -199,10 +237,12 @@ void enableMotors()
|
||||
switch (cmd)
|
||||
{
|
||||
case 0:
|
||||
stopPrintSession();
|
||||
motorsOff();
|
||||
sendAck();
|
||||
break;
|
||||
case 1:
|
||||
startPrintSessionIfNeeded();
|
||||
motorsOn();
|
||||
sendAck();
|
||||
break;
|
||||
@@ -216,10 +256,12 @@ void enableMotors()
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
stopPrintSession();
|
||||
motorsOff();
|
||||
sendAck();
|
||||
break;
|
||||
case 1:
|
||||
startPrintSessionIfNeeded();
|
||||
motorsOn();
|
||||
sendAck();
|
||||
break;
|
||||
@@ -318,8 +360,11 @@ void makeComInterface()
|
||||
};
|
||||
|
||||
registerCommands(SCmd);
|
||||
SCmd.setLineHandler(captureSerialProtocolLine);
|
||||
#ifdef ESP32
|
||||
registerCommands(g_BLECmd);
|
||||
g_BLECmd.setLineHandler(captureBleProtocolLine);
|
||||
registerCommands(g_WifiCmd);
|
||||
g_WifiCmd.setLineHandler(captureWifiProtocolLine);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef ESP32
|
||||
constexpr char kDeviceNamePrefix[] = "EggBot_";
|
||||
#endif
|
||||
|
||||
int clampServoAngle(int angle)
|
||||
{
|
||||
if (angle < 0)
|
||||
@@ -36,6 +40,20 @@ uint_fast16_t servoSpeedFromRate(int rate)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void buildDeviceName(char *nameBuffer, size_t bufferSize)
|
||||
{
|
||||
if ((nameBuffer == NULL) || (bufferSize == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Tasmota-style chip ID uses the lower 24 bits of the ESP32 efuse MAC.
|
||||
const uint32_t chipId = static_cast<uint32_t>(ESP.getEfuseMac() & 0xFFFFFFULL);
|
||||
snprintf(nameBuffer, bufferSize, "%s%06X", kDeviceNamePrefix, chipId);
|
||||
}
|
||||
#endif
|
||||
|
||||
void updateStepCorrectionFactors()
|
||||
{
|
||||
if (g_iRotMicrostep <= 0)
|
||||
|
||||
@@ -3,12 +3,19 @@
|
||||
namespace {
|
||||
constexpr size_t kLogCapacity = 80;
|
||||
constexpr size_t kLogLineLength = 160;
|
||||
constexpr size_t kIncomingLogCapacity = 128;
|
||||
constexpr size_t kIncomingLogLineLength = SERIALCOMMAND_BUFFER + 24;
|
||||
|
||||
char g_logLines[kLogCapacity][kLogLineLength];
|
||||
uint32_t g_logSeq[kLogCapacity];
|
||||
size_t g_logWritePos = 0;
|
||||
uint32_t g_nextLogSeq = 1;
|
||||
|
||||
char g_incomingLogLines[kIncomingLogCapacity][kIncomingLogLineLength];
|
||||
uint32_t g_incomingLogSeq[kIncomingLogCapacity];
|
||||
size_t g_incomingLogWritePos = 0;
|
||||
uint32_t g_nextIncomingLogSeq = 1;
|
||||
|
||||
void appendJsonEscaped(String &out, const char *text) {
|
||||
out += "\"";
|
||||
for (size_t i = 0; text[i] != '\0'; ++i) {
|
||||
@@ -40,6 +47,18 @@ void appendJsonEscaped(String &out, const char *text) {
|
||||
}
|
||||
out += "\"";
|
||||
}
|
||||
|
||||
const char *transportLabel(ProtocolTransport transport) {
|
||||
switch (transport) {
|
||||
case PROTOCOL_TRANSPORT_BLE:
|
||||
return "BLE";
|
||||
case PROTOCOL_TRANSPORT_WIFI:
|
||||
return "WIFI";
|
||||
case PROTOCOL_TRANSPORT_SERIAL:
|
||||
default:
|
||||
return "SERIAL";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Log(const String &message) {
|
||||
@@ -89,3 +108,45 @@ String buildLogsJson(uint32_t sinceSeq) {
|
||||
output += "}";
|
||||
return output;
|
||||
}
|
||||
|
||||
void captureIncomingPrintLine(const char *line, ProtocolTransport transport) {
|
||||
if ((line == NULL) || (line[0] == '\0')) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
g_incomingLogLines[g_incomingLogWritePos],
|
||||
kIncomingLogLineLength,
|
||||
"[%010lu] %s %s",
|
||||
static_cast<unsigned long>(millis()),
|
||||
transportLabel(transport),
|
||||
line
|
||||
);
|
||||
g_incomingLogSeq[g_incomingLogWritePos] = g_nextIncomingLogSeq++;
|
||||
g_incomingLogWritePos = (g_incomingLogWritePos + 1) % kIncomingLogCapacity;
|
||||
}
|
||||
|
||||
String buildIncomingPrintLogText() {
|
||||
String output;
|
||||
output.reserve(4096);
|
||||
|
||||
for (size_t i = 0; i < kIncomingLogCapacity; ++i) {
|
||||
const size_t idx = (g_incomingLogWritePos + i) % kIncomingLogCapacity;
|
||||
if (g_incomingLogSeq[idx] == 0) {
|
||||
continue;
|
||||
}
|
||||
output += g_incomingLogLines[idx];
|
||||
output += "\n";
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void clearIncomingPrintLog() {
|
||||
for (size_t i = 0; i < kIncomingLogCapacity; ++i) {
|
||||
g_incomingLogSeq[i] = 0;
|
||||
g_incomingLogLines[i][0] = '\0';
|
||||
}
|
||||
g_incomingLogWritePos = 0;
|
||||
g_nextIncomingLogSeq = 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user