From e8c0fb42d445ce208351e03adf34a7e2dcc00891 Mon Sep 17 00:00:00 2001 From: Jonas Diemer Date: Fri, 26 Dec 2025 02:13:40 +0100 Subject: [PATCH] Network details QR code (#113) Using QRCode library from pio to generate the QR code. Done: - Display QR code for URL in network mode - minor fixes of layout - Display QR for URL in AP mode - Display QR for AP in AP mode --------- Co-authored-by: Dave Allie --- .github/workflows/ci.yml | 6 --- platformio.ini | 1 + .../network/CrossPointWebServerActivity.cpp | 46 ++++++++++++++++++- .../network/WifiSelectionActivity.cpp | 7 ++- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1d91ec5..be9a6e59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,6 @@ jobs: - uses: actions/checkout@v6 with: submodules: recursive - - uses: actions/cache@v5 - with: - path: | - ~/.cache/pip - ~/.platformio/.cache - key: ${{ runner.os }}-pio - uses: actions/setup-python@v6 with: python-version: '3.14' diff --git a/platformio.ini b/platformio.ini index 9cd5df2e..0fd766a3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,6 +40,7 @@ lib_deps = InputManager=symlink://open-x4-sdk/libs/hardware/InputManager EInkDisplay=symlink://open-x4-sdk/libs/display/EInkDisplay ArduinoJson @ 7.4.2 + QRCode @ 0.0.1 [env:default] extends = base diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index 34b1a3a8..c370bc28 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -4,8 +4,12 @@ #include #include #include +#include #include +#include +#include + #include "NetworkModeSelectionActivity.h" #include "WifiSelectionActivity.h" #include "config.h" @@ -336,6 +340,28 @@ void CrossPointWebServerActivity::render() const { } } +void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std::string& data) { + // Implementation of QR code calculation + // The structure to manage the QR code + QRCode qrcode; + uint8_t qrcodeBytes[qrcode_getBufferSize(4)]; + Serial.printf("[%lu] [WEBACT] QR Code (%lu): %s\n", millis(), data.length(), data.c_str()); + + qrcode_initText(&qrcode, qrcodeBytes, 4, ECC_LOW, data.c_str()); + const uint8_t px = 6; // pixels per module + for (uint8_t cy = 0; cy < qrcode.size; cy++) { + for (uint8_t cx = 0; cx < qrcode.size; cx++) { + if (qrcode_getModule(&qrcode, cx, cy)) { + // Serial.print("**"); + renderer.fillRect(x + px * cx, y + px * cy, px, px, true); + } else { + // Serial.print(" "); + } + } + // Serial.print("\n"); + } +} + void CrossPointWebServerActivity::renderServerRunning() const { // Use consistent line spacing constexpr int LINE_SPACING = 28; // Space between lines @@ -344,7 +370,7 @@ void CrossPointWebServerActivity::renderServerRunning() const { if (isApMode) { // AP mode display - center the content block - const int startY = 55; + int startY = 55; renderer.drawCenteredText(UI_FONT_ID, startY, "Hotspot Mode", true, BOLD); @@ -354,6 +380,13 @@ void CrossPointWebServerActivity::renderServerRunning() const { renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 2, "Connect your device to this WiFi network", true, REGULAR); + renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, + "or scan QR code with your phone to connect to Wifi.", true, REGULAR); + // Show QR code for URL + std::string wifiConfig = std::string("WIFI:T:WPA;S:") + connectedSSID + ";P:" + "" + ";;"; + drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig); + + startY += 6 * 29 + 3 * LINE_SPACING; // Show primary URL (hostname) std::string hostnameUrl = std::string("http://") + AP_HOSTNAME + ".local/"; renderer.drawCenteredText(UI_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, BOLD); @@ -361,8 +394,12 @@ void CrossPointWebServerActivity::renderServerRunning() const { // Show IP address as fallback std::string ipUrl = "or http://" + connectedIP + "/"; renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, ipUrl.c_str(), true, REGULAR); - renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "Open this URL in your browser", true, REGULAR); + + // Show QR code for URL + renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "or scan QR code with your phone:", true, + REGULAR); + drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl); } else { // STA mode display (original behavior) const int startY = 65; @@ -385,6 +422,11 @@ void CrossPointWebServerActivity::renderServerRunning() const { renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, REGULAR); renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser", true, REGULAR); + + // Show QR code for URL + drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo); + renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "or scan QR code with your phone:", true, + REGULAR); } renderer.drawButtonHints(UI_FONT_ID, "« Exit", "", "", ""); diff --git a/src/activities/network/WifiSelectionActivity.cpp b/src/activities/network/WifiSelectionActivity.cpp index 80e46ceb..68c6481e 100644 --- a/src/activities/network/WifiSelectionActivity.cpp +++ b/src/activities/network/WifiSelectionActivity.cpp @@ -150,6 +150,11 @@ void WifiSelectionActivity::processWifiScanResults() { std::sort(networks.begin(), networks.end(), [](const WifiNetworkInfo& a, const WifiNetworkInfo& b) { return a.rssi > b.rssi; }); + // Show networks with PW first + std::sort(networks.begin(), networks.end(), [](const WifiNetworkInfo& a, const WifiNetworkInfo& b) { + return a.hasSavedPassword && !b.hasSavedPassword; + }); + WiFi.scanDelete(); state = WifiSelectionState::NETWORK_LIST; selectedNetworkIndex = 0; @@ -581,7 +586,7 @@ void WifiSelectionActivity::renderConnecting() const { if (state == WifiSelectionState::SCANNING) { renderer.drawCenteredText(UI_FONT_ID, top, "Scanning...", true, REGULAR); } else { - renderer.drawCenteredText(READER_FONT_ID, top - 30, "Connecting...", true, BOLD); + renderer.drawCenteredText(READER_FONT_ID, top - 40, "Connecting...", true, BOLD); std::string ssidInfo = "to " + selectedSSID; if (ssidInfo.length() > 25) {