Leon
Published © MIT

TravelPad no wifi notpad!

TravelPad is a notpad that dosnt need any wifi just a phone or laptop. it runs on an arduino r4 wifi or arduino q 2gb or 4gb.

BeginnerWork in progress10 hours16
TravelPad no wifi notpad!

Things used in this project

Hardware components

Arduino Uno R4 WiFi
Arduino Uno R4 WiFi
One option for this
×1
Arduino UNO Q
Arduino UNO Q
Other option for this project
×1
Usb-c Cable
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Main code

CSS
this is the code for TravelPad
#include "WiFiS3.h"
#include "ArduinoGraphics.h" // Declared above matrix for text features
#include "Arduino_LED_Matrix.h"
#include <ArduinoMDNS.h>    // Standard cross-board mDNS library
#include <EEPROM.h>

// Universal Portable Credentials
const char* ssid = "TravelNotepad";
const char* pass = "ta-ard-p";

WiFiServer server(80);
WiFiUDP udpConn;             // Required backend wrapper for mDNS listener
MDNS mdns(udpConn);
ArduinoLEDMatrix matrix;

const int MAX_NOTE_SIZE = 400;  
const int EEPROM_START_ADDR = 0; 

String globalScrollText = "";
bool triggerScroll = false;

// Custom Matrix Icons (12x8 layouts mapped to 32-bit integers)
const uint32_t book_icon[]  = { 0x3fe20230, 0x20220220, 0x2023fe00 };
const uint32_t smile_icon[] = { 0x30c40212, 0x0c00c000, 0x1230c000 };
const uint32_t heart_icon[] = { 0x183060c6, 0x0c40c204, 0x10830000 };

void setup() {
  Serial.begin(9600);
  matrix.begin();
  
  Serial.println("Initializing TravelNotepad Portable OS...");
  WiFi.beginAP(ssid, pass);
  
  server.begin();

  // START UNIVERSAL mDNS ENGINE
  // This broadcasts http://tn.local to any connected laptop or smartphone
  if (mdns.begin(WiFi.localIP(), "tn")) {
    Serial.println("mDNS responder configured! Address: http://tn.local");
  } else {
    Serial.println("Error initializing mDNS engine.");
  }
  
  matrix.loadFrame(book_icon);
}

void saveToEEPROM(String data) {
  int len = data.length();
  if (len > MAX_NOTE_SIZE - 1) len = MAX_NOTE_SIZE - 1;
  for (int i = 0; i < len; i++) {
    EEPROM.write(EEPROM_START_ADDR + i, data[i]);
  }
  EEPROM.write(EEPROM_START_ADDR + len, '\0');
}

String readFromEEPROM() {
  String data = "";
  for (int i = 0; i < MAX_NOTE_SIZE; i++) {
    char c = EEPROM.read(EEPROM_START_ADDR + i);
    if (c == '\0' || (byte)c == 255) break;
    data += c;
  }
  return data;
}

void loop() {
  // Constantly feed the mDNS engine background cycles to process text translation
  mdns.run();

  // 1. MATRIX SCROLL ENGINE
  if (triggerScroll && globalScrollText.length() > 0) {
    triggerScroll = false;
    matrix.beginDraw();
    matrix.stroke(0xFFFFFF);
    matrix.textScrollSpeed(60); 
    matrix.textFont(Font_5x7);
    matrix.beginText(0, 1, 0xFFFFFF);
    matrix.print("   " + globalScrollText + "   ");
    matrix.endText(SCROLL_LEFT);
    matrix.endDraw();
  }

  // 2. WEB WORKSPACE ENGINE
  WiFiClient client = server.available();
  if (client) {
    String currentLine = "";
    String requestBody = "";
    bool isPostRequest = false;
    int contentLength = 0;

    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        
        if (currentLine.startsWith("POST /save")) isPostRequest = true;
        if (currentLine.startsWith("Content-Length: ")) {
          contentLength = currentLine.substring(16).toInt();
        }

        if (c == '\n') {
          if (currentLine.length() == 0) {
            if (isPostRequest && contentLength > 0) {
              for (int i = 0; i < contentLength; i++) {
                requestBody += (char)client.read();
              }
              if (requestBody.startsWith("note=")) {
                String newNote = requestBody.substring(5);
                newNote.replace("+", " ");
                while (newNote.indexOf("%") >= 0) {
                  int index = newNote.indexOf("%");
                  String hex = newNote.substring(index + 1, index + 3);
                  char decodedChar = (char)strtol(hex.c_str(), NULL, 16);
                  newNote = newNote.substring(0, index) + decodedChar + newNote.substring(index + 3);
                }
                saveToEEPROM(newNote);
                globalScrollText = newNote; 
                triggerScroll = true;
              }
            }

            if (currentLine.indexOf("GET /effect1") >= 0) matrix.loadFrame(smile_icon);
            if (currentLine.indexOf("GET /effect2") >= 0) matrix.loadFrame(heart_icon);
            if (currentLine.indexOf("GET /clear") >= 0) {
              matrix.clear();
              matrix.loadFrame(book_icon);
            }

            String savedNote = readFromEEPROM();
            int charCount = savedNote.length();

            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connection: close");
            client.println();
            
            client.println("<!DOCTYPE html><html><head>");
            client.println("<meta name='viewport' content='width=device-width, initial-scale=1.0'>");
            client.println("<style>");
            client.println("body{font-family:sans-serif;background:#0d1117;color:#c9d1d9;margin:0;padding:15px;}");
            client.println(".box{max-width:600px;margin:auto;background:#161b22;padding:20px;border-radius:12px;border:1px solid #30363d;}");
            client.println("textarea{width:96%;height:140px;background:#0d1117;color:#fff;border:1px solid #30363d;border-radius:6px;padding:10px;font-size:16px;}");
            client.println(".btn{background:#238636;color:white;border:none;padding:12px;border-radius:6px;font-weight:bold;width:100%;font-size:16px;cursor:pointer;}");
            client.println(".tool-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:15px;}");
            client.println(".t-btn{background:#21262d;color:#58a6ff;border:1px solid #30363d;padding:10px;border-radius:6px;font-size:13px;cursor:pointer;}");
            client.println("</style></head><body><div class='box'>");
            
            client.println("<h3 style='color:#58a6ff;margin-top:0;'>πŸ““ Universal TravelNotepad OS</h3>");
            client.print("<p style='font-size:12px;color:#8b949e;'>Storage: <b>");
            client.print(charCount);
            client.println("</b> / 400 Characters.</p>");
            
            client.println("<form action='/save' method='POST'>");
            client.print("<textarea name='note'>");
            client.print(savedNote);
            client.println("</textarea><br><br>");
            client.println("<input type='submit' class='btn' value='πŸ’Ύ Save Note & Scroll on Matrix'></form>");
            
            client.println("<h4 style='color:#8b949e;margin-bottom:5px;margin-top:20px;'>πŸ› οΈ Matrix Tools</h4>");
            client.println("<div class='tool-grid'>");
            client.println("<button class='t-btn' onclick=\"fetch('/effect1')\">😊 Smile</button>");
            client.println("<button class='t-btn' onclick=\"fetch('/effect2')\">❀️ Heart</button>");
            client.println("<button class='t-btn' onclick=\"fetch('/clear')\" style='color:#f85149;'>Reset</button>");
            client.println("</div>");
            
            client.println("</div></body></html>");
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

Credits

Leon
1 project β€’ 0 followers

Comments