Search Code

Mokano ya ESP32-S3 RGB LED Matrix Projɛ́ 3 - Mokanda na phone ya mbɔ́kɔ

Mokano ya ESP32-S3 RGB LED Matrix Projɛ́ 3 - Mokanda na phone ya mbɔ́kɔ

Projet 3 – Matrice ya Contrôle ya Maloba Longwa na Lapi na Yo (Texte HTTP)

Na projet oyo, ESP32-S3 RGB LED Matrix ezali na lokasa moko ya web mpo okoka kobongola maloba oyo ezali kotambola, langi, direction, mpe vitesse directement longwa na lapi na yo to ordinateur. Okoki te kosenga application mosusu – kaka navigateur web. Boye, module oyo ekoma display ya texte ya Wi-Fi moke oyo okoki kozongisa na temps réel.

Baprojɛ́ sɔ̌kɔ́ na motóbá na série oyo ezali kolimbolama mpe kotalisama na vidéo moko ya YouTube. Vidéo yango moko ezali na lokasa oyo, mpo okoka komona ndenge nini interface web ezali komonana mpe ndenge nini maloba ebongwanaka mbala moko na matrice. Code ya source mobimba ya projet oyo ezali komatama automatiquement na nse ya article, mpe okoki kosomba module ya ESP32-S3 RGB LED Matrix na magazini ya affiliés oyo ezali na nse ya code.

Na article oyo, tozali kolimbola ndenge nini logique ya réseau ezali kosala (Wi-Fi ya ndako vs point d'accès) mpe ba paramètres nini okoki kobongola na code mpo na personaliser comportement.

Vue générale ya Module ESP32-S3 RGB LED Matrix

Matériel ezali kaka moko na baprojɛ́ mosusu na série oyo: carte ya microcontrôleur ESP32-S3 na matrice ya 8×8 RGB LED oyo ezali na kati mpe capteur ya mouvement QMI8658C na nsima. Port USB-C ezali kosalelama mpo na puissance mpe programmation, mpe ba pins na pembeni ezali kaka mpo na IO mosusu.:contentReference[oaicite:0]{index=0}

  • ESP32-S3 – microcontrôleur oyo ekoki na Wi-Fi mpe Bluetooth.
  • Matrice 8×8 RGB – ba LED RGB 64 oyo ekoki na adresse mpo na maloba mpe graphiques.
  • Accéléromètre QMI8658C – esalelamaka na baprojɛ́ ya tilt mpe ya jeu.
  • Port USB – epesaka puissance na carte mpe ematisi sketches longwa na Arduino IDE.
  • Ba pins oyo ezali polele – epesaka nzela na ba capteurs to ba actionneurs mosusu soki esengeli.
  • Ba boutons Boot/Reset – mpo na upload ya firmware mpe kofanda lisusu.

Mpo na Projet 3, élément ya ntina mingi ezali Wi-Fi ya ESP32, oyo epesaka carte nzela ya kosala lokola serveur web moke mpo na lokasa ya contrôle ya maloba.:contentReference[oaicite:1]{index=1}

Baprojɛ́ oyo ezali na Vidéo (Ba timestamps)

Vidéo moko ya série oyo elimboli baprojɛ́ na motóbá. Mpo na référence ya mbangu:

  • 00:00 – Introduction
  • 02:01 – Installation ya ba cartes ESP32
  • 03:32 – Installation ya ba bibliothèques
  • 05:32 – Projet 1: Dot oyo ezali kotambola
  • 11:11 – Projet 2: Texte oyo ezali kotambola
  • 12:59Projet 3: Texte HTTP (projet oyo)
  • 16:41 – Projet 4: Dot ya Tilt
  • 18:55 – Projet 5: Flèche na likolo
  • 20:02 – Projet 6: Jeu ya Cible

Tokosɛngɛ yo otala section ya Texte HTTP na vidéo wana ozali kosala na article oyo. Vidéo emonisi ndenge nini lokasa ya web ezali kosalema na ESP32 mpe ndenge nini kobongola maloba, langi, mpe vitesse emonanaka mbala moko na matrice ya LED.:contentReference[oaicite:2]{index=2}

Installation ya ba cartes ESP32 na Arduino IDE

Soki osilaki kosala Projets 1 to 2, configuration ya carte esili mpe okoki kolongwa na section oyo. Sinon, landa ba étapes oyo na Arduino IDE:

  1. Fungola File > Preferences mpe bakisa URL ya ba cartes ESP32 na “Additional Boards Manager URLs”.
  2. Kende na Tools > Board > Boards Manager…, luka ESP32, mpe installe paquet officiel ya ESP32.
  3. Pona carte ya ESP32-S3 RGB Matrix oyo ebongi na Tools > Board.
  4. Kangisa module na USB mpe pona port série oyo ebongi na Tools > Port.

Soki ezali na support ya carte ESP32 mpe port oyo ebongi te, sketch ya serveur web ekotomboka te.

Installation ya NeoMatrix mpe ba bibliothèques oyo esengeli

Projet oyo esalelaka ba bibliothèques kaka na projet ya texte oyo ezali kotambola:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library

Installe na Library Manager:

  1. Fungola Sketch > Include Library > Manage Libraries….
  2. Luka Adafruit NeoMatrix mpe pesa Install.
  3. Ambola installation ya ba dépendances (Adafruit GFX mpe Adafruit NeoPixel).

Nsima ya installation, okomona ba exemples ya NeoMatrix mpe NeoPixel na File > Examples.

Ba modes mibale ya Wi-Fi na Projet 3

Konsepti ya ntina mingi na projet oyo ezali ete ESP32 ekoki kosala na ba modes mibale ya kokesene:

  1. Mode Station (STA) – ESP32 ekangamaka na réseau Wi-Fi ya ndako na yo oyo ezali.
  2. Mode Access Point (AP) – ESP32 esalaka réseau na yango moko ya Wi-Fi soki Wi-Fi ya ndako ezali te.

Ba modes mibale oyo esalelaka interface web kaka moko: lokasa ya HTML oyo ewutaka na ESP32 moko, epai okoki kobongola maloba, langi, direction ya kotambola, mpe vitesse.:contentReference[oaicite:3]{index=3}

Mode 1 – Kokangama na Wi-Fi ya Ndako (Mode Station)

Na mode Station, ESP32 ekangamaka na réseau Wi-Fi ya ndako to ya bureau. Oyo ezali mode oyo ebongi mingi tango nyonso routeur na yo ezali mpo na:

  • Lapi na yo mpe ordinateur na yo esili kokangama na réseau Wi-Fi yango moko.
  • Okoki kotia adresse IP ya ESP32 na navigateur na yo mpe kokamba maloba longwa na esaleli nyonso na réseau yango.

Na section ya paramètres ya sketch, okopesa SSID mpe mot de passe ya Wi-Fi na yo:


// Makambo ya Wi-Fi ya ndako (Station mode)
const char* WIFI_SSID = "YourHomeWiFi";
const char* WIFI_PASS = "YourHomePassword";

Sima na board ebandi, ezali koluka kokɔta na WIFI_SSID. Soki elongaki, code ekomi adresi ya IP oyo epesameli na Serial Monitor, na ndakisa:


Connected to WiFi
IP address: 192.168.1.16

Mpo na kokamba maloba:

  1. Tiká ete telefɔ́nɛ́ na yo to PC ezali kokɔta na réseau Wi-Fi moko (na ndakisa, YourHomeWiFi).
  2. Fungola navigateur mpe kotisa adresi ya IP oyo ekomamaki, lokola http://192.168.1.16/.
  3. Lokasa ya contrôle ekomonana, mpe okoki kokoma maloba, kopona couleur, kopona direction, mpe kobongisa vitesse ya scrolling.

Mode 2 – Access Point ya libanga (AP Mode)

Soki ESP32 ekoki te kokɔta na Wi-Fi ya ndako na yo (mot de passe mabe, réseau ezali te, to ozali kosalela module na libándá), sketch ekomi automatiquement na mode Access Point. Na mode AP, ESP32 moko akoma hotspot ya Wi-Fi na kombo na yango moko mpe mot de passe na yango.

Na projet oyo, paramètres ya AP ezali ya kokanga:


// Access Point (AP) credentials (fallback mode)
const char* AP_SSID = "ESP32";
const char* AP_PASS = "password";

Soki Station mode elongi te, module ekokɔta na mode AP mpe ebandi kopanza réseau Wi-Fi oyo babengi ESP32. Mpo na kokamba matrice:

  1. Na telefɔ́nɛ́ na yo to ordinateur, fungola paramètres ya Wi-Fi mpe kokɔta na réseau ESP32.
  2. Kotisa mot de passe password (lokola ekomami na code).
  3. Sima ya kokɔta, fungola navigateur mpe kende na http://192.168.4.1/ (IP ya défaut mpo na mode AP ya ESP32).
  4. Lokasa moko ya contrôle ekomonana, mpe okoki kobongola maloba, couleur, vitesse, mpe direction.

Komportement oyo ya fallback esalaka ete projet ezala utile na esika nyonso: na ndako, na laboratoire, to na environnement ya démonstration epai wapi routeur ezali te.

Projet 3 – Paramètres ya Minene na Code

Sketch ya HTTP Text mobimba ezali na se ya article oyo na site. Awa tokomi kaka configuration ya minene oyo okoki kobongola.

Paramètres ya Wi-Fi mpe Access Point

Na likoló ya sketch, okomona section ya configuration ya Wi-Fi. Bongola kaka ba credentials ya Station (Wi-Fi ya ndako); paramètres ya AP ezali généralement na défaut:


// ---------- Wi-Fi SETTINGS ----------

// Home Wi-Fi (Station mode)
const char* WIFI_SSID = "YourHomeWiFi";      // tia SSID ya routeur na yo awa
const char* WIFI_PASS = "YourHomePassword";  // tia mot de passe ya routeur na yo awa

// Fallback Access Point (AP mode)
const char* AP_SSID = "ESP32";               // kombo ya AP ya kokanga
const char* AP_PASS = "password";            // mot de passe ya AP ya kokanga

Komportement:

  • Soki WIFI_SSID mpe WIFI_PASS ezali malamu mpe réseau ezali wapi → ESP32 ekokɔta lokola appareil Wi-Fi ya libanda (Station mode).
  • Soki connexion elongi te sima ya temps oyo esili → ESP32 ebandi AP na yango moko na AP_SSID mpe AP_PASS.

Pin ya Matrice, Taille, mpe Luminosité

Paramètres oyo ezali lokola na ba projets oyo eleki:


// Matrix configuration
const int MATRIX_PIN    = 14;   // pin ya données ya matrice RGB
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

// Luminosité ya affichage mobimba (0–255)
uint8_t matrixBrightness = 40;  // bongola mpo na environnement na yo

Bombá MATRIX_PIN na 14 mpo na board oyo. Okoki komatisa matrixBrightness soki olingi pole mingi, kasi ba valeurs ya se ezali malamu mpo na kotala pene.

Maloba ya Défaut mpe Paramètres ya Scrolling

Soki board ebandi, ezali kolakisa message ya liboso kino ofungoli lokasa web mpe okomi mosusu. Okoki kobongola maloba ya défaut na configuration:


// Message ya défaut oyo elakisamaka na ebandeli
String currentText = "Robojax";   // ekobongolama sima na web UI

Bokɛ́ti ya scrolling mosusu ekolamelaka na ba variables oyo web interface ebongolaka:


// Délai ya scrolling na millisecondes (moke = mbangu)
int scrollDelayMs = 50;

// Direction ya scrolling: 0=gauche, 1=droite, 2=likoló, 3=na se
int scrollDirection = 0;   // défaut: scroll na gauche

Lokasa web etindaka ba valeurs ya sika kolandana na ba choix ya slider mpe bouton. Na côté Arduino, olingi koyeba kaka ete:

  • Kokitisa scrollDelayMs esalaka ete maloba etambola mbangu.
  • Komatisa scrollDelayMs esalaka ete etambola malɛmbɛ.
  • Kobongola scrollDirection esalaka ete scrolling ekende na gauche, droite, likoló, to na se.

Couleur ya Maloba (Ekolamelaka na Lokasa Web)

Couleur ya maloba ekolamelaka na ba valeurs misato ya 0–255 (ngiɔ, vert, bleu). Ebongolamaka tango nyonso oponi couleur ya sika na lokasa web:


// Couleur ya maloba ya sik’oyo (R, G, B)
uint8_t textRed   = 255;
uint8_t textGreen = 255;
uint8_t textBlue  = 255;

Sima ya kopona couleur na navigateur mpe ko-kliquer na Apply, ESP32 ekokabwaka ba valeurs RGB mpe ebongola ba variables oyo misato; maloba ekomi na couleur ya sika na matrice mbala moko. Na vidéo, komportement oyo elakisamaka na ba changements ya couleurs mingi, na ndakisa ya ngiɔ, vert, mpe bleu.

Résumé

Projet 3 ebongolaka ESP32-S3 RGB LED Matrix na yo na affichage ya maloba oyo ezali na Wi-Fi mobimba, oyo okoki kokamba na appareil nyonso oyo ezali na navigateur web. Sketch esalemi mpo na kozala robuste:

  • Ezalaka mosɔtɔlɔ na Wi-Fi ya ndako na yo na nkombo ya SSID mpe password oyo otie.
  • Soki elongi te, ekoma ya moko esika ya kofungola na nkombo ESP32 mpe password password.
  • Na ba ndenge nyonso mibale, kofungola adresi IP ya semba na navigateur ekolakisa lokasa moko ya kontrolɛlɛ mpo na makomi, langi, direction, mpe vitesse.

Kode ya HTTP Text mobimba ezali awa na nse ya lisolo oyo (ezali komema automatiquement na site ya web). Mpo na etape na etape ya kolakisa mpe ndenge text ezali kobongwana na tango ya solo, tala video na eteni ya Projɛ 3. Soki olingi kosala projɛ yango moko, okoki kosomba module ya ESP32-S3 RGB LED Matrix na ba liens affiliés oyo ezali na nse ya kode.

Images

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
Langue: 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();
  }
}

Mokili na bisika

Fichiers📁

Fritzing File