Raadi Koodka

Mashruuca ESP32-S3 RGB LED Matrix Project 3 - Qoraal ka yimid taleefanka gacanta

Mashruuca ESP32-S3 RGB LED Matrix Project 3 - Qoraal ka yimid taleefanka gacanta

Mashruuc 3 – Xakamaynta Qoraalka Matrix-ka Taleefankaaga (HTTP Text)

Mashruucan, ESP32-S3 RGB LED Matrix wuxuu martigeliyaa bog yar oo web ah si aad u beddesho qoraalka wareegaya, midabka, jihada, iyo xawaaraha si toos ah taleefankaaga ama kombiyuutarkaaga. Uma baahnid app gaar ah – kaliya browser web. Tani waxay ka dhigaysaa qalabkan bandhig qoraal oo Wi-Fi yar oo aad cusboonaysiin karto waqti toos ah.

Dhammaan lixda mashruuc ee taxanahan waxaa lagu sharaxay oo lagu muujiyay hal fiidiyow oo YouTube ah. Isla fiidiyowga ayaa ku dhex jira boggan, si aad si sax ah u aragto sida web interface-ka u eg yahay iyo sida qoraalka isla markiiba ugu cusboonaado matrix-ka. Koodhka buuxa ee mashruucan waxaa si toos ah loogu shubay hoosta maqaalka, waxaadna ka iibsan kartaa qalabka ESP32-S3 RGB LED Matrix dukaamada la xidhiidha ee ku qoran hoosta qaybta koodhka.

Maqaalkan waxaan diiradda saareynaa sida logic-ga shabakadu u shaqeeyo (Wi-Fi guriga vs access point) iyo goorma aad ku beddeli karto koodhka si aad u qaabayso hab-dhaqanka.

Guudmarka Qalabka ESP32-S3 RGB LED Matrix

Qalabku wuxuu la mid yahay dhammaan mashruucyada kale ee taxanahan: guddiga microcontroller-ka ESP32-S3 oo leh matrix RGB 8×8 oo ku dhex dhisan iyo sensor dhaqdhaqaaqa QMI8658C oo dhabarka ku yaal. Dekadda USB-C waxaa loo isticmaalaa koronto iyo barnaamijyada, biinanka ku wareegsan cidhifyada ayaa weli diyaar u ah IO kale.:contentReference[oaicite:0]{index=0}

  • ESP32-S3 – microcontroller Wi-Fi iyo Bluetooth awood u leh.
  • Matrix RGB 8×8 – 64 LED RGB oo la xakameyn karo oo loogu talagalay qoraal iyo sawirro.
  • Accelerometer QMI8658C – loo isticmaalo mashruucyada leexinta iyo ciyaaraha.
  • Dekadda USB – koronto siisaa guddiga oo soo galiyaa sketches-ka Arduino IDE.
  • Biinanka la soo bandhigay – waxay u oggolaadaan sensorro ama actuators dheeri ah haddii loo baahdo.
  • Badhamada Boot/Reset – loogu talagalay soo gelinta firmware-ka iyo dib u bilowga.

Mashruuca 3, sifada ugu muhiimsan waa Wi-Fi-ga ESP32, kaas oo u oggolaanaya guddiga inuu u shaqeeyo sidii server web yar oo loogu talagalay bogga xakamaynta qoraalka.:contentReference[oaicite:1]{index=1}

Mashruucyada Ku Qoran Fiidiyowga (Waqtiyada)

Hal fiidiyow oo taxanahan ah ayaa daboolaya dhammaan lixda mashruuc. Tixraac degdeg ah:

  • 00:00 – Hordhac
  • 02:01 – Rakibidda guddiyada ESP32
  • 03:32 – Rakibidda maktabadaha
  • 05:32 – Mashruuca 1: Dhibicda Dhaqaaqaysa
  • 11:11 – Mashruuca 2: Wareegga Qoraalka
  • 12:59Mashruuca 3: HTTP Text (mashruucan)
  • 16:41 – Mashruuca 4: Dhibicda Leexinta
  • 18:55 – Mashruuca 5: Fallaro Kor
  • 20:02 – Mashruuca 6: Ciyaarta Bartilmaameedka

Waxaa lagu dhiirigelinayaa inaad daawato qaybta HTTP Text ee fiidiyowga inta aad la shaqeyneysay maqaalkan. Fiidiyowgu wuxuu muujinayaa sida bogga web-ka uu u soo saaro ESP32 iyo sida beddelka qoraalka, midabka, iyo xawaaraha isla markiiba looga tarjumayo LED matrix-ka.:contentReference[oaicite:2]{index=2}

Rakibidda Guddiyada ESP32 ee Arduino IDE

Haddii aad horey u dhammeysatay Mashruucyada 1 ama 2, dejinta guddiga waa la dhammeeyay waxaadna ka gudbi kartaa qaybtan. Haddii kale, raac tillaabooyinkan Arduino IDE:

  1. Fur File > Preferences oo ku dar URL-ka guddiyada ESP32 ee “Additional Boards Manager URLs”.
  2. Tag Tools > Board > Boards Manager…, raadi ESP32, oo rakib xirmada rasmiga ah ee ESP32.
  3. Dooro guddiga saxda ah ee ESP32-S3 RGB Matrix ee Tools > Board.
  4. Ku xir qalabka USB-ga oo dooro dekedda saxda ah ee Tools > Port.

Haddii aan la helin taageerada saxda ah ee guddiga ESP32 iyo dekedda saxda ah, sketch-ka web-server-ku ma soo geli doono.

Rakibidda NeoMatrix iyo Maktabadaha Loo Baahan Yahay

Mashruucan wuxuu isticmaalaa isla maktabadihii mashruucii hore ee wareegga qoraalka:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library

Ku rakib Manager-ka Maktabadda:

  1. Fur Sketch > Include Library > Manage Libraries….
  2. Raadi Adafruit NeoMatrix oo guji Install.
  3. Aqbal rakibidda ku-tiirsanaanta (Adafruit GFX iyo Adafruit NeoPixel).

Marka la rakibo, waa inaad ku aragtaa tusaalooyinka NeoMatrix iyo NeoPixel ee hoos yimaada File > Examples.

Laba Hab oo Wi-Fi ah ee Mashruuca 3

Fikradda ugu muhiimsan ee mashruucan waa in ESP32 uu ku shaqeyn karo laba hab oo kala duwan:

  1. Habka Station (STA) – ESP32 wuxuu ku xidhmaa shabakadda Wi-Fi-ga ee gurigaaga ee jirta.
  2. Habka Access Point (AP) – ESP32 wuxuu abuuraa shabakad Wi-Fi oo u gaar ah haddii Wi-Fi guriga uusan diyaar ahayn.

Labada hab waxay isticmaalaan isla web interface-ka: bog HTML ah oo laga soo saaro ESP32 laftiisa, halkaas oo aad ku beddeli karto qoraalka, midabka, jihada wareegga, iyo xawaaraha.:contentReference[oaicite:3]{index=3}

Habka 1 – Ku Xidhnaanshaha Wi-Fi Guriga (Habka Station)

Habka Station, ESP32 wuxuu ku biiraa shabakadda Wi-Fi-ga guriga ama xafiiskaaga. Kani waa habka la doorbido marka router-kaagu uu diyaar yahay sababtoo ah:

  • Taleefankaaga iyo kombiyuutarkaagu waxay horey ugu xidhnaayeen isla shabakadda Wi-Fi-ga.
  • Waxaad tilmaami kartaa browser-kaaga cinwaanka IP-ga ee ESP32 oo waxaad ka xakameyn kartaa qoraalka qalab kasta oo ku yaal shabakaddaas.

Qaybta dejinta ee sketch-ka, waxaad siisaa SSID-ka Wi-Fi-gaaga iyo erayga sirta ah:

Guriga Wi-Fi credentials-ka (Qaabka Station) const char* WIFI_SSID = "WiFi-gurigaaga"; const char* WIFI_PASS = "Password-ka-gurigaaga"; Marka board-ku uu boot-garo, wuxuu isku dayaa inuu ku xirmo WIFI_SSID. Haddii uu ku guuleysto, koodhku wuxuu daabacaa cinwaanka IP-ga ee loo qoondeeyay Serial Monitor-ka, tusaale ahaan: Connected to WiFi IP address: 192.168.1.16 Si aad u xakamayso qoraalka: 1. Hubi in taleefankaaga ama PC-gaagu uu ku xiran yahay isku shabakadda Wi-Fi-ga (tusaale ahaan, YourHomeWiFi). 2. Fur browser-ka oo geli cinwaanka IP-ga ee la daabacay, sida http://192.168.1.16/. 3. Bogga xakamaynta ayaa soo bixi doona, isagoo kuu oggolaanaya inaad ku qorto qoraal, doorato midab, doorato jihada, oo aad hagaajiso xawaaraha is-dhaafista. Qaabka 2 – Access Point Madaxbanaan (Qaabka AP) Haddii ESP32-ga uu awoodi waayo inuu ku xirmo Wi-Fi-gaaga guriga (password khaldan, shabakad aan la heli karin, ama aad isticmaalayso module-ka dibadda), sketch-ku wuxuu si toos ah ugu dhacaa Qaabka Access Point. Qaabka AP, ESP32-ga laftiisu wuxuu noqdaa hotspot Wi-Fi ah oo leh magaciisa shabakadeed iyo password-kiisa. Mashruucan, dejinta AP-ga waxay u go'an tahay sida: // Access Point (AP) credentials-ka (qaabka fallback) const char* AP_SSID = "ESP32"; const char* AP_PASS = "password"; Marka Qaabka Station uu guuldareysto, module-ku wuxuu u beddelaa Qaabka AP wuxuuna bilaabaa inuu baahiyo shabakad Wi-Fi ah oo la yiraahdo ESP32. Si aad u xakamayso matrix-ka: 1. Taleefankaaga ama kombuyuutarkaaga, fur dejinta Wi-Fi-ga oo ku xir shabakadda ESP32. 2. Geli password-ka password (sida lagu qeexay koodhka). 3. Markaad ku xiranto, fur browser-ka oo aad http://192.168.4.1/ (IP-ga caadiga ah ee Qaabka AP ee ESP32). 4. Isla bogga xakamaynta ayaa soo baxaya, isagoo kuu oggolaanaya inaad beddesho qoraalka, midabka, xawaaraha, iyo jihada. Dhaqankan fallback-ka ah wuxuu mashruuca ka dhigayaa mid waxtar leh meel kasta: guriga, shaybaarka, ama jawi demo ah oo aan router la heli karin. Mashruuca 3 – Dejinta Muhiimka ah ee Koodhka Sketch-ka HTTP Text ee buuxa waxaa hoos ku shubay website-ku maqaalkan. Halkan waxaanu dokumentaynaa kaliya doorashooyinka qaabaynta ee ugu muhiimsan ee aad u badan tahay inaad wax ka beddesho. Dejinta Wi-Fi iyo Access Point Dusha sketch-ka waxaad ka heli doontaa qaybta qaabaynta Wi-Fi. Kaliya beddel credentials-ka Station (Wi-Fi guriga); dejinta AP-ga waxaa caadi ahaan loo hayaa sida default-ka: // ---------- DEJINTA WI-FI ---------- // Wi-Fi guriga (Qaabka Station) const char* WIFI_SSID = "YourHomeWiFi"; // halkan ku qor SSID-ka router-kaaga const char* WIFI_PASS = "YourHomePassword"; // halkan ku qor password-ka router-kaaga // Fallback Access Point (Qaabka AP) const char* AP_SSID = "ESP32"; // magaca AP-ga go'an const char* AP_PASS = "password"; // password-ka AP-ga go'an Dhaqanka: - Haddii WIFI_SSID iyo WIFI_PASS ay sax yihiin oo shabakaddu ay jirto → ESP32 wuxuu ku xirmaa sidii qalab Wi-Fi caadi ah (Qaabka Station). - Haddii xiriirku uu guuldareysto ka dib waqti-go'an → ESP32 wuxuu bilaabaa AP-ga u gaarka ah isagoo isticmaalaya AP_SSID iyo AP_PASS. Pin-ka Matrix-ka, Cabbirka, iyo Iftiinka Dejintan waxay la mid tahay mashruucyadii hore: // Qaabaynta Matrix-ka const int MATRIX_PIN = 14; // pin-ka xogta ee RGB matrix const int MATRIX_WIDTH = 8; const int MATRIX_HEIGHT = 8; // Iftiinka guud ee bandhigga (0–255) uint8_t matrixBrightness = 40; // ku hagaaji deegaankaaga Ku hay MATRIX_PIN at 14 board-gan. Waxaad kordhin kartaa matrixBrightness haddii aad u baahan tahay iftiin dheeri ah, laakiin qiimayaasha hoose ayaa ku habboon daawashada dhow. Qoraalka Caadiga ah iyo Dejinta Is-dhaafista Marka board-ku uu bilaabmo, wuxuu soo bandhigayaa farriin bilow ah ilaa aad furto bogga web-ka oo aad ku qorto mid cusub. Waxaad beddeli kartaa qoraalka caadiga ah ee qaabaynta: // Farriinta caadiga ah ee lagu muujiyo bilowga String currentText = "Robojax"; // waxaa laga beddeli karaa web UI-ga markii dambe Inta ka hartay dhaqanka is-dhaafista waxaa xakameeya doorsoomayaal ay cusboonaysiiso interface-ka web-ka: // Dib u dhaca is-dhaafista ee milliseken (hoose = ka dhakhso badan) int scrollDelayMs = 50; // Jihada is-dhaafista: 0=bidix, 1=midig, 2=kor, 3=hoos int scrollDirection = 0; // default: u is-dhaaf bidix Bogga web-ku wuxuu soo diraa qiimayaal cusub oo ku salaysan slider-ka iyo doorashooyinka badhanka. Dhinaca Arduino-ga, kaliya waxaad u baahan tahay inaad ogaato in: - Hoos u dhaca scrollDelayMs wuxuu qoraalka ka dhigayaa mid si dhakhso leh u dhaqaaqa. - Kordhinta scrollDelayMs wuxuu ka dhigayaa mid si gaabis ah u dhaqaaqa. - Beddelka scrollDirection wuxuu u beddelaa bidix, midig, kor, ama hoos. Midabka Qoraalka (Waxaa Xakameeya Bogga Web-ka) Midabka qoraalka waxaa xakameeya saddex qiime oo 0–255 ah (guduud, cagaar, buluug). Waxaa la cusboonaysiiyaa mar kasta oo aad doorato midab cusub oo ku yaal bogga web-ka: // Midabka qoraalka hadda (R, G, B) uint8_t textRed = 255; uint8_t textGreen = 255; uint8_t textBlue = 255; Markaad doorato midab browser-ka oo aad gujiso Apply, ESP32-ga wuxuu falanqeeyaa qiimayaasha RGB wuxuuna cusboonaysiiyaa saddexda doorsoome; qoraalku isla markiiba wuxuu beddelaa midabka matrix-ka. Fiidiyowga, dhaqankan waxaa lagu muujiyay beddello midab oo badan, oo ay ku jiraan tusaalooyin guduud, cagaar, iyo buluug. Soo Koobid Mashruuca 3 wuxuu ESP32-S3 RGB LED Matrix-kaaga u beddelaa bandhig qoraal oo si buuxda wireless ah oo aad ku xakameyn karto adigoo isticmaalaya qalab kasta oo leh browser web ah. Sketch-ku waxaa loo qaabeeyey inuu ahaado mid adag:
  • Waxa uu marka hore isku dayaa in uu ku xidhmao Wi-Fi-gaaga guriga isagoo isticmaalaya SSID-ka iyo erayga sirta ah ee aad qaawisay.
  • Haddii taas guuldareysato, si otomaatig ah wuxuu u noqdaa barta gelitaanka oo magaceedu yahay ESP32 iyo erayga sirta ah password.
  • Labada qaabba, furista cinwaanka IP-ga saxda ah ee browser-ka waxay muujinaysaa bogga xakamaynta isku midka ah ee qoraalka, midabka, jihada, iyo xawaaraha.

Koodhka HTTP Text ee dhammaystiran ayaa ka hoos yaal maqaalkan (si otomaatig ah ayaa lagu shubaa websaydhka). Si aad u hesho tallaabo-tallaabo buuxda iyo muujin toos ah oo ku saabsan sida qoraalku ugu cusboonaado waqtiga dhabta ah, hubi inaad daawato qaybta Mashruuca 3 ee fiidiyowga. Haddii aad rabto inaad adigu dhisto mashruuca, waxaad sidoo kale iibsan kartaa qalabka ESP32-S3 RGB LED Matrix adigoo isticmaalaya xiriiriyeyaasha la xidhiidha ee hoos ku qoran koodhka.

Sawirro

ESP32 S3 Matrix
ESP32 S3 Matrix
ESP32 S3 Matrix  pin out
ESP32 S3 Matrix pin out
ESP32-S3_RGB_8x8_matrix-3
ESP32-S3_RGB_8x8_matrix-3
ESP32 S3 Matrix displaying rainbow heart
ESP32 S3 Matrix displaying rainbow heart
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix1
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3_RGB_8x8_matrix-2
ESP32-S3 RGB Matrix- Mobile Phone Text
ESP32-S3 RGB Matrix- Mobile Phone Text
801-ESP32-S3 RGB LED Matrix Project 3 - Text from mobile phone
Luqadda: C++
/*
  Project 4: HTTP Text Scroll – ESP32-S3 RGB LED Matrix (Waveshare)

  - Connects to your home WiFi (station mode, with AP fallback).
  - Serves a web page where you can set:
      * Text
      * Color
      * Display ON/OFF
      * Scroll direction (Left / Right / Up / Down)
      * Scroll delay (speed)
  - Supports 8×8 RGB LED matrix using Adafruit_NeoMatrix.

  ▶️ Video Tutorial:
  https://youtu.be/JKLuYrRcLMI

  📄 Resources & Code Page:
  https://robojax.com/your-resources-page-here

  HTTP_Text_Scroll
*/

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

// ======================= WIFI SETTINGS =========================
// Home WiFi (change these to your router credentials)
const char* WIFI_SSID = "Biseem";
const char* WIFI_PASS = "wan9&Jang~";

// Fallback Access Point
const char* AP_SSID = "ESP32";
const char* AP_PASS = "password";

// ======================= MATRIX SETTINGS =======================

#define MATRIX_PIN    14
#define MATRIX_WIDTH  8
#define MATRIX_HEIGHT 8

// 0, 1, 2, or 3 – adjust if text orientation is wrong with USB up
#define MATRIX_ROTATION 0
#define BRIGHTNESS 15

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
  MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
  NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
  NEO_RGB + NEO_KHZ800
);

// ======================= SCROLL STATE ==========================

enum ScrollDir {
  DIR_LEFT = 0,
  DIR_RIGHT,
  DIR_UP,
  DIR_DOWN
};

String   scrollText  = "Robojax";
uint16_t textColor   = 0xFFFF;  // default white
bool     displayOn   = true;
ScrollDir currentDir = DIR_LEFT;

// 1 step every this many ms (lower = faster)
unsigned long scrollInterval = 80;
unsigned long lastScrollTime = 0;

// Horizontal scroll position
int scrollX = MATRIX_WIDTH;
int scrollY = 0;              // top row

// State for vertical per-letter scroll
int vertCharIndex = 0;        // which character of the string
int vertY         = MATRIX_HEIGHT;    // vertical position of that character

// ======================= WEB SERVER ============================

WebServer server(80);

// ======================= HTML PAGE ============================

const char MAIN_page[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ESP32 Text Scroll</title>
<style>
  body {
    font-family: Arial, sans-serif;
    background: #111;
    color: #eee;
    text-align: center;
    margin: 0;
    padding: 10px;
  }
  .container {
    max-width: 360px;
    width: 100%%;
    margin: 0 auto;
    background: #222;
    padding: 12px;
    border-radius: 10px;
    box-sizing: border-box;
  }
  input[type="text"] {
    width: 100%%;
    padding: 8px;
    box-sizing: border-box;
    border-radius: 5px;
    border: 1px solid #444;
    background: #111;
    color: #eee;
    margin-bottom: 10px;
  }
  .row {
    margin: 10px 0;
  }
  .label {
    display: block;
    margin-bottom: 5px;
    text-align: left;
  }
  .toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  .arrow-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: repeat(3, 50px);
    gap: 8px;
    justify-content: center;
    margin-top: 10px;
  }
  .arrow-btn {
    background: #333;
    border: 1px solid #555;
    color: #eee;
    font-size: 18px;
    border-radius: 10px;
    cursor: pointer;
    width: 100%%;
    height: 100%%;
  }
  .arrow-btn.active {
    background: #0a84ff;
  }
  .arrow-btn:disabled {
    opacity: 0.5;
    cursor: default;
  }
  button#applyBtn {
    margin-top: 15px;
    padding: 10px 20px;
    border-radius: 8px;
    border: none;
    background: #0a84ff;
    color: #fff;
    font-size: 16px;
    cursor: pointer;
  }
  button#applyBtn:active {
    transform: scale(0.97);
  }
</style>
</head>
<body>
  <div class="container">
    <h2>Robojax ESP32-S3 Matrix Text Scroll</h2>

    <div class="row">
      <span class="label">Text to scroll:</span>
      <input type="text" id="text" value="Hello" />
    </div>

    <div class="row">
      <span class="label">Color:</span>
      <input type="color" id="color" value="#ffffff" />
    </div>

    <div class="row">
      <span class="label">Scroll Delay (fast → slow):</span>
      <input
        type="range"
        id="speed"
        min="20"
        max="300"
        value="80"
        oninput="document.getElementById('speedVal').innerText = this.value + ' ms';"
      />
      <div id="speedVal" style="text-align:right;font-size:12px;margin-top:4px;">
        80 ms
      </div>
    </div>

    <div class="row">
      <label class="toggle">
        <input type="checkbox" id="power" checked />
        <span>Display ON</span>
      </label>
    </div>

    <div class="row">
      <span class="label">Scroll Direction:</span>
      <div class="arrow-grid">
        <div></div>
        <button class="arrow-btn" id="btnUp" onclick="setDir('up')">&#9650;</button>
        <div></div>

        <button class="arrow-btn" id="btnLeft" onclick="setDir('left')">&#9664;</button>
        <div></div>
        <button class="arrow-btn" id="btnRight" onclick="setDir('right')">&#9654;</button>

        <div></div>
        <button class="arrow-btn" id="btnDown" onclick="setDir('down')">&#9660;</button>
        <div></div>
      </div>
    </div>

    <button id="applyBtn" onclick="sendUpdate()">Apply</button>
    <p id="status"></p>
  </div>

<script>
  let currentDir = 'left';

  function setDir(dir) {
    currentDir = dir;
    document.querySelectorAll('.arrow-btn').forEach(b => b.classList.remove('active'));
    if (dir === 'up')    document.getElementById('btnUp').classList.add('active');
    if (dir === 'down')  document.getElementById('btnDown').classList.add('active');
    if (dir === 'left')  document.getElementById('btnLeft').classList.add('active');
    if (dir === 'right') document.getElementById('btnRight').classList.add('active');
    sendUpdate();
  }

  function sendUpdate() {
    const text  = document.getElementById('text').value;
    const color = document.getElementById('color').value;
    const power = document.getElementById('power').checked ? '1' : '0';
    const speed = document.getElementById('speed').value;

    const url = `/update?text=${encodeURIComponent(text)}&color=${encodeURIComponent(color)}&power=${power}&dir=${currentDir}&speed=${speed}`;

    fetch(url)
      .then(r => r.text())
      .then(t => {
        document.getElementById('status').innerText = t;
      })
      .catch(err => {
        document.getElementById('status').innerText = 'Error sending update';
      });
  }

  // Set default active
  setDir('left');
</script>
</body>
</html>
)rawliteral";

// ======================= HELPERS ===============================

bool isHexChar(char c) {
  return (c >= '0' && c <= '9') ||
         (c >= 'a' && c <= 'f') ||
         (c >= 'A' && c <= 'F');
}

String urlDecode(const String &src) {
  String result;
  result.reserve(src.length());
  for (size_t i = 0; i < src.length(); i++) {
    char c = src[i];
    if (c == '+') {
      result += ' ';
    } else if (c == '%' && i + 2 < src.length()) {
      char h1 = src[i + 1];
      char h2 = src[i + 2];
      if (isHexChar(h1) && isHexChar(h2)) {
        char hex[3] = {h1, h2, 0};
        int val = (int)strtol(hex, nullptr, 16);
        result += (char)val;
        i += 2;
      } else {
        result += c;
      }
    } else {
      result += c;
    }
  }
  return result;
}

uint16_t colorFromHex(const String &hex) {
  // Expect "#RRGGBB" or "RRGGBB"
  String c = hex;
  if (c.startsWith("#")) c.remove(0, 1);
  if (c.length() != 6) {
    // default white
    return matrix.Color(255, 255, 255);
  }
  long value = strtol(c.c_str(), NULL, 16);
  uint8_t r = (value >> 16) & 0xFF;
  uint8_t g = (value >> 8) & 0xFF;
  uint8_t b = (value) & 0xFF;
  return matrix.Color(r, g, b);
}

void resetScrollPosition() {
  int textWidth  = scrollText.length() * 6;  // default font ~6 px per char
  int textHeight = 8;                        // 5x7 font fits in 8

  switch (currentDir) {
    case DIR_LEFT:
      // Start from just outside the right edge
      scrollX = MATRIX_WIDTH;
      scrollY = 0;
      break;

    case DIR_RIGHT:
      // Start from just outside the left edge
      scrollX = -textWidth;
      scrollY = 0;
      break;

    case DIR_UP:
      // Per-letter vertical scroll, starting with first character below matrix
      vertCharIndex = 0;
      vertY = MATRIX_HEIGHT;   // 8 → enters from bottom
      break;

    case DIR_DOWN:
      // Per-letter vertical scroll, starting with first character above matrix
      vertCharIndex = 0;
      vertY = -textHeight;     // -8 → enters from top
      break;
  }
}

// ======================= HTTP HANDLERS =========================

void handleRoot() {
  server.send_P(200, "text/html", MAIN_page);
}

void handleUpdate() {
  if (server.hasArg("text")) {
    String txt = urlDecode(server.arg("text"));
    if (txt.length() == 0) {
      scrollText = " ";
    } else {
      scrollText = txt;
    }
  }

  if (server.hasArg("color")) {
    String hex = server.arg("color");
    textColor = colorFromHex(hex);
  }

  if (server.hasArg("power")) {
    String p = server.arg("power");
    displayOn = (p == "1");
  }

  if (server.hasArg("dir")) {
    String d = server.arg("dir");
    if (d == "left")      currentDir = DIR_LEFT;
    else if (d == "right") currentDir = DIR_RIGHT;
    else if (d == "up")    currentDir = DIR_UP;
    else if (d == "down")  currentDir = DIR_DOWN;
  }

  if (server.hasArg("speed")) {
    String s = server.arg("speed");
    int val = s.toInt();

    // simple safety clamp
    if (val < 10)   val = 10;    // very fast
    if (val > 1000) val = 1000;  // 1 second max

    scrollInterval = (unsigned long)val;
    // Serial.print("Scroll interval set to ");
    // Serial.print(scrollInterval);
    // Serial.println(" ms");
  }

  resetScrollPosition();
  server.send(200, "text/plain", "Updated");
}

// ======================= SCROLL LOGIC ==========================

void drawScroll() {
  if (!displayOn) {
    matrix.fillScreen(0);
    matrix.show();
    return;
  }

  int textWidth  = scrollText.length() * 6;
  int textHeight = 8;

  matrix.fillScreen(0);
  matrix.setTextSize(1);
  matrix.setTextWrap(false);
  matrix.setTextColor(textColor);

  // -------- HORIZONTAL SCROLL (LEFT / RIGHT) --------
  if (currentDir == DIR_LEFT || currentDir == DIR_RIGHT) {
    matrix.setCursor(scrollX, 0);
    matrix.print(scrollText);
    matrix.show();

    if (currentDir == DIR_LEFT) {
      scrollX--;
      if (scrollX < -textWidth) {
        scrollX = MATRIX_WIDTH;
      }
    } else { // DIR_RIGHT
      scrollX++;
      if (scrollX > MATRIX_WIDTH) {
        scrollX = -textWidth;
      }
    }
    return;
  }

  // -------- VERTICAL SCROLL (UP / DOWN) – PER LETTER --------

  if (scrollText.length() == 0) {
    matrix.show();
    return;
  }

  // Current character
  char c = scrollText[vertCharIndex];

  int charWidth  = 6;
  int baseX = (MATRIX_WIDTH - charWidth) / 2;  // center horizontally

  matrix.setCursor(baseX, vertY);
  matrix.print(c);
  matrix.show();

  if (currentDir == DIR_UP) {
    // Move character upwards
    vertY--;
    if (vertY < -textHeight) {
      // This character is fully passed, go to next
      vertY = MATRIX_HEIGHT;
      vertCharIndex++;
      if (vertCharIndex >= scrollText.length()) {
        vertCharIndex = 0; // loop back to first character
      }
    }
  } else if (currentDir == DIR_DOWN) {
    // Move character downwards
    vertY++;
    if (vertY > MATRIX_HEIGHT) {
      // This character is fully passed, go to next
      vertY = -textHeight;
      vertCharIndex++;
      if (vertCharIndex >= scrollText.length()) {
        vertCharIndex = 0; // loop back
      }
    }
  }
}

// ======================= WIFI INIT =============================

void startAPFallback() {
  Serial.println("Starting AP fallback...");
  WiFi.mode(WIFI_AP);
  bool apOk = WiFi.softAP(AP_SSID, AP_PASS);
  if (apOk) {
    Serial.print("AP started. SSID: ");
    Serial.print(AP_SSID);
    Serial.print("  IP: ");
    Serial.println(WiFi.softAPIP());
  } else {
    Serial.println("Failed to start AP.");
  }
}

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  Serial.print("Connecting to WiFi ");
  Serial.print(WIFI_SSID);

  unsigned long startAttempt = millis();
  const unsigned long timeout = 10000; // 10s

  while (WiFi.status() != WL_CONNECTED && (millis() - startAttempt) < timeout) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();

  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("Connected. IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("WiFi connect failed, starting AP fallback.");
    startAPFallback();
  }
}

// ======================= SETUP & LOOP ==========================

void setup() {
  Serial.begin(115200);
  delay(500);

  // Matrix init
  matrix.begin();
  matrix.setRotation(MATRIX_ROTATION);
  matrix.setBrightness(BRIGHTNESS);
  matrix.fillScreen(0);
  matrix.show();

  // WiFi
  connectWiFi();

  // Web server routes
  server.on("/", handleRoot);
  server.on("/update", handleUpdate);
  server.onNotFound([]() {
    server.send(404, "text/plain", "Not found");
  });
  server.begin();
  Serial.println("HTTP server started.");

  resetScrollPosition();
}

void loop() {
  server.handleClient();

  unsigned long now = millis();
  if (now - lastScrollTime >= scrollInterval) {
    lastScrollTime = now;
    drawScroll();
  }
}

Waad u baahan tahay

Kheyraadka & Tixraacyada

Faylasha📁

Faylka Fritzing