From 90446b31b07ee6565b955d0290352cf73fe20570 Mon Sep 17 00:00:00 2001 From: Miles Raymond Date: Mon, 2 Feb 2026 13:08:53 -0800 Subject: [PATCH] add unique hostname support --- .../network/CalibreConnectActivity.cpp | 18 ++++++++++-- .../network/CrossPointWebServerActivity.cpp | 28 ++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/activities/network/CalibreConnectActivity.cpp b/src/activities/network/CalibreConnectActivity.cpp index 8aa60c40..6a30fc68 100644 --- a/src/activities/network/CalibreConnectActivity.cpp +++ b/src/activities/network/CalibreConnectActivity.cpp @@ -11,7 +11,19 @@ #include "fontIds.h" namespace { -constexpr const char* HOSTNAME = "crosspoint"; + // Generate hostname dynamically based on device MAC address + String getDeviceHostname() { + static String deviceHostname; + if (deviceHostname.length() == 0) { + uint64_t chipId = ESP.getEfuseMac(); + // Extract last 6 hex digits (24 bits) for serial number + uint32_t serialNum = (uint32_t)(chipId & 0xFFFFFF); + char hostname[32]; + snprintf(hostname, sizeof(hostname), "XTeinkX4-%06X", serialNum); + deviceHostname = String(hostname); + } + return deviceHostname; + } } // namespace void CalibreConnectActivity::taskTrampoline(void* param) { @@ -94,9 +106,9 @@ void CalibreConnectActivity::startWebServer() { state = CalibreConnectState::SERVER_STARTING; updateRequired = true; - if (MDNS.begin(HOSTNAME)) { + if (MDNS.begin(getDeviceHostname().c_str())) { // mDNS is optional for the Calibre plugin but still helpful for users. - Serial.printf("[%lu] [CAL] mDNS started: http://%s.local/\n", millis(), HOSTNAME); + Serial.printf("[%lu] [CAL] mDNS started: http://%s.local/\n", millis(), getDeviceHostname().c_str()); } webServer.reset(new CrossPointWebServer()); diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index c6af1497..fe163219 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -19,10 +19,24 @@ namespace { // AP Mode configuration constexpr const char* AP_SSID = "CrossPoint-Reader"; constexpr const char* AP_PASSWORD = nullptr; // Open network for ease of use -constexpr const char* AP_HOSTNAME = "crosspoint"; constexpr uint8_t AP_CHANNEL = 1; constexpr uint8_t AP_MAX_CONNECTIONS = 4; +// Static cached hostname for the device +static String deviceHostname; + +// Generate hostname dynamically based on device MAC address +String getDeviceHostname() { + if (deviceHostname.length() == 0) { + // Extract last 6 hex digits (24 bits) for serial number + uint32_t serialNum = (uint32_t)(ESP.getEfuseMac() & 0xFFFFFF); + char hostname[32]; + snprintf(hostname, sizeof(hostname), "XTeinkX4-%06X", serialNum); + deviceHostname = String(hostname); + } + return deviceHostname; +} + // DNS server for captive portal (redirects all DNS queries to our IP) DNSServer* dnsServer = nullptr; constexpr uint16_t DNS_PORT = 53; @@ -181,8 +195,8 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) exitActivity(); // Start mDNS for hostname resolution - if (MDNS.begin(AP_HOSTNAME)) { - Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME); + if (MDNS.begin(getDeviceHostname().c_str())) { + Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), getDeviceHostname().c_str()); } // Start the web server @@ -234,8 +248,8 @@ void CrossPointWebServerActivity::startAccessPoint() { Serial.printf("[%lu] [WEBACT] IP: %s\n", millis(), connectedIP.c_str()); // Start mDNS for hostname resolution - if (MDNS.begin(AP_HOSTNAME)) { - Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME); + if (MDNS.begin(getDeviceHostname().c_str())) { + Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), getDeviceHostname().c_str()); } else { Serial.printf("[%lu] [WEBACT] WARNING: mDNS failed to start\n", millis()); } @@ -439,7 +453,7 @@ void CrossPointWebServerActivity::renderServerRunning() const { startY += 6 * 29 + 3 * LINE_SPACING; // Show primary URL (hostname) - std::string hostnameUrl = std::string("http://") + AP_HOSTNAME + ".local/"; + std::string hostnameUrl = std::string("http://") + getDeviceHostname().c_str() + ".local/"; renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, EpdFontFamily::BOLD); // Show IP address as fallback @@ -468,7 +482,7 @@ void CrossPointWebServerActivity::renderServerRunning() const { renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 2, webInfo.c_str(), true, EpdFontFamily::BOLD); // Also show hostname URL - std::string hostnameUrl = std::string("or http://") + AP_HOSTNAME + ".local/"; + std::string hostnameUrl = std::string("or http://") + getDeviceHostname().c_str() + ".local/"; renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str()); renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser");