Search Code

ESP32-S3 RGB LED میٹرکس پروجیکٹ 3 - موبائل فون سے ٹیکسٹ

ESP32-S3 RGB LED میٹرکس پروجیکٹ 3 - موبائل فون سے ٹیکسٹ

پروجیکٹ 3 – اپنے فون سے میٹرکس ٹیکسٹ کنٹرول کریں (HTTP ٹیکسٹ)

اس پروجیکٹ میں ESP32-S3 RGB LED میٹرکس ایک چھوٹا ویب پیج ہوسٹ کرتا ہے تاکہ آپ اسکرولنگ ٹیکسٹ، رنگ، سمت، اور رفتار کو براہِ راست اپنے فون یا کمپیوٹر سے تبدیل کر سکیں۔ آپ کو کسی علیحدہ ایپ کی ضرورت نہیں – صرف ایک ویب براؤزر کافی ہے۔ یہ ماجیول کو ایک چھوٹا وائی-فائی ٹیکسٹ ڈسپلے بناتا ہے جسے آپ ریئل ٹائم میں اپ ڈیٹ کر سکتے ہیں۔

اس سیریز کے تمام چھ پروجیکٹس ایک یوٹیوب ویڈیو میں وضاحت اور مظاہرے کے ساتھ پیش کیے گئے ہیں۔ وہی ویڈیو اس صفحے پر ایمبیڈڈ ہے، تاکہ آپ بالکل دیکھ سکیں کہ ویب انٹرفیس کیسا لگتا ہے اور ٹیکسٹ میٹرکس پر فوری طور پر کیسے اپ ڈیٹ ہوتا ہے۔ اس پروجیکٹ کا مکمل سورس کوڈ مضمون کے نیچے خودکار طور پر لوڈ ہوتا ہے، اور آپ ESP32-S3 RGB LED میٹرکس ماجیول کو کوڈ سیکشن کے نیچے درج ایفلی ایٹ اسٹورز سے خرید سکتے ہیں۔

اس مضمون میں ہم اس بات پر توجہ مرکوز کرتے ہیں کہ نیٹ ورک منطق کیسے کام کرتی ہے (ہوم وائی-فائی بمقابلہ ایکسیس پوائنٹ) اور آپ رویے کو حسبِ ضرورت بنانے کے لیے کوڈ میں کون سی سیٹنگز تبدیل کر سکتے ہیں۔

ESP32-S3 RGB LED میٹرکس ماجیول کا جائزہ

ہارڈویئر وہی ہے جو اس سیریز کے دیگر تمام پروجیکٹس میں ہے: ایک ESP32-S3 مائیکروکنٹرولر بورڈ جس میں بلٹ ان 8×8 RGB LED میٹرکس اور پچھلی جانب QMI8658C موشن سینسر ہے۔ USB-C پورٹ پاور اور پروگرامنگ کے لیے استعمال ہوتا ہے، اور کناروں کے ارد گرد موجود پن دوسرے IO کے لیے دستیاب رہتے ہیں۔

  • ESP32-S3 – وائی-فائی اور بلوٹوتھ کی صلاحیت رکھنے والا مائیکروکنٹرولر۔
  • 8×8 RGB میٹرکس – ٹیکسٹ اور گرافکس کے لیے 64 ایڈریس ایبل RGB LEDs۔
  • QMI8658C ایکسلرومیٹر – ٹیلٹ اور گیم پروجیکٹس میں استعمال ہوتا ہے۔
  • USB پورٹ – بورڈ کو پاور دیتا ہے اور Arduino IDE سے اسکیچز اپ لوڈ کرتا ہے۔
  • کھلے پن – ضرورت پڑنے پر اضافی سینسرز یا ایکچیو ایٹرز کی اجازت دیتے ہیں۔
  • بوٹ/ری سیٹ بٹن – فرم ویئر اپ لوڈ اور ری اسٹارٹ کے لیے۔

پروجیکٹ 3 کے لیے، سب سے اہم خصوصیت ESP32 کی وائی-فائی ہے، جو بورڈ کو ٹیکسٹ کنٹرول پیج کے لیے ایک چھوٹے ویب سرور کے طور پر کام کرنے دیتی ہے۔

ویڈیو میں شامل پروجیکٹس (ٹائم اسٹیمپس)

اس سیریز کی ایک ویڈیو تمام چھ پروجیکٹس کا احاطہ کرتی ہے۔ فوری حوالے کے لیے:

  • 00:00 – تعارف
  • 02:01 – ESP32 بورڈز انسٹال کرنا
  • 03:32 – لائبریریز انسٹال کرنا
  • 05:32 – پروجیکٹ 1: موونگ ڈاٹ
  • 11:11 – پروجیکٹ 2: ٹیکسٹ اسکرول
  • 12:59پروجیکٹ 3: HTTP ٹیکسٹ (یہ پروجیکٹ)
  • 16:41 – پروجیکٹ 4: ٹیلٹ ڈاٹ
  • 18:55 – پروجیکٹ 5: ارو اپ
  • 20:02 – پروجیکٹ 6: ٹارگٹ گیم

آپ کو اس مضمون کے ساتھ کام کرتے ہوئے ویڈیو میں HTTP ٹیکسٹ سیکشن دیکھنے کی ترغیب دی جاتی ہے۔ ویڈیو دکھاتی ہے کہ ویب پیج ESP32 کے ذریعے کیسے تیار ہوتا ہے اور ٹیکسٹ، رنگ، اور رفتار کو تبدیل کرنا LED میٹرکس پر فوری طور پر کیسے ظاہر ہوتا ہے۔

Arduino IDE میں ESP32 بورڈز انسٹال کرنا

اگر آپ نے پہلے ہی پروجیکٹس 1 یا 2 مکمل کر لیے ہیں، تو بورڈ سیٹ اپ ہو چکا ہے اور آپ اس سیکشن کو چھوڑ سکتے ہیں۔ بصورت دیگر، Arduino IDE میں ان مراحل پر عمل کریں:

  1. File > Preferences کھولیں اور ESP32 بورڈز کا URL “Additional Boards Manager URLs” میں شامل کریں۔
  2. Tools > Board > Boards Manager… پر جائیں، ESP32 تلاش کریں، اور آفیشل ESP32 پیکیج انسٹال کریں۔
  3. Tools > Board سے صحیح ESP32-S3 RGB میٹرکس بورڈ منتخب کریں۔
  4. ماجیول کو USB کے ذریعے جوڑیں اور Tools > Port کے تحت صحیح سیریل پورٹ منتخب کریں۔

مناسب ESP32 بورڈ سپورٹ اور صحیح پورٹ کے بغیر، ویب سرور اسکیچ اپ لوڈ نہیں ہوگا۔

NeoMatrix اور مطلوبہ لائبریریز انسٹال کرنا

یہ پروجیکٹ پچھلے ٹیکسٹ اسکرول پروجیکٹ جیسی ہی لائبریریز استعمال کرتا ہے:

  • Adafruit NeoMatrix
  • Adafruit NeoPixel
  • Adafruit GFX Library

لائبریری مینیجر کے ذریعے انسٹال کریں:

  1. Sketch > Include Library > Manage Libraries… کھولیں۔
  2. Adafruit NeoMatrix تلاش کریں اور Install پر کلک کریں۔
  3. ڈیپنڈنسیز (Adafruit GFX اور Adafruit NeoPixel) کی انسٹالیشن قبول کریں۔

انسٹال ہونے کے بعد، آپ کو File > Examples کے تحت NeoMatrix اور NeoPixel مثال کے اسکیچز نظر آئیں گے۔

پروجیکٹ 3 میں دو وائی-فائی موڈز

اس پروجیکٹ میں سب سے اہم تصور یہ ہے کہ ESP32 دو مختلف موڈز میں کام کر سکتا ہے:

  1. اسٹیشن (STA) موڈ – ESP32 آپ کے موجودہ ہوم وائی-فائی نیٹ ورک سے جڑتا ہے۔
  2. ایکسیس پوائنٹ (AP) موڈ – اگر ہوم وائی-فائی دستیاب نہ ہو تو ESP32 اپنا وائی-فائی نیٹ ورک بناتا ہے۔

دونوں موڈز ایک ہی ویب انٹرفیس استعمال کرتے ہیں: ایک HTML صفحہ جو خود ESP32 سے پیش کیا جاتا ہے، جہاں آپ ٹیکسٹ، رنگ، اسکرول سمت، اور رفتار تبدیل کر سکتے ہیں۔

موڈ 1 – ہوم وائی-فائی سے جڑیں (اسٹیشن موڈ)

اسٹیشن موڈ میں، ESP32 آپ کے ہوم یا آفس وائی-فائی نیٹ ورک میں شامل ہوتا ہے۔ یہ ترجیحی موڈ ہے جب بھی آپ کا راؤٹر دستیاب ہو کیونکہ:

  • آپ کا فون اور کمپیوٹر پہلے سے اسی وائی-فائی نیٹ ورک سے جڑے ہوتے ہیں۔
  • آپ اپنے براؤزر کو ESP32 کے IP ایڈریس پر لے جا سکتے ہیں اور اس نیٹ ورک پر کسی بھی ڈیوائس سے ٹیکسٹ کنٹرول کر سکتے ہیں۔

اسکیچ کے سیٹنگز سیکشن میں، آپ اپنا وائی-فائی SSID اور پاس ورڈ فراہم کرتے ہیں:

// گھر کے وائی فائی اسناد (اسٹیشن موڈ) const char* WIFI_SSID = "YourHomeWiFi"; const char* WIFI_PASS = "YourHomePassword";

بورڈ بوٹ ہونے کے بعد، یہ WIFI_SSID سے منسلک ہونے کی کوشش کرتا ہے۔ اگر کامیاب ہو جائے تو، کوڈ تفویض کردہ IP ایڈریس کو سیریل مانیٹر پر پرنٹ کرتا ہے، مثال کے طور پر:


Connected to WiFi
IP address: 192.168.1.16

متن کو کنٹرول کرنے کے لیے:

  1. یقینی بنائیں کہ آپ کا فون یا PC اسی وائی فائی نیٹ ورک سے منسلک ہے (مثال کے طور پر، YourHomeWiFi
  2. ایک براؤزر کھولیں اور پرنٹ شدہ IP ایڈریس درج کریں، جیسے http://192.168.1.16/۔ :contentReference[oaicite:4]{index=4}
  3. کنٹرول صفحہ ظاہر ہوگا، جس سے آپ متن ٹائپ کر سکتے ہیں، رنگ منتخب کر سکتے ہیں، سمت منتخب کر سکتے ہیں، اور اسکرول کی رفتار کو ایڈجسٹ کر سکتے ہیں۔

موڈ 2 – اسٹینڈ اکیلے ایکسیس پوائنٹ (AP موڈ)

اگر ESP32 آپ کے گھر کے وائی فائی سے منسلک نہیں ہو سکتا (غلط پاس ورڈ، نیٹ ورک دستیاب نہیں، یا آپ ماجیول باہر استعمال کر رہے ہیں)، تو اسکیچ خود بخود ایکسیس پوائنٹ موڈ میں واپس آ جاتا ہے۔ AP موڈ میں، ESP32 خود ایک وائی فائی ہاٹ سپاٹ بن جاتا ہے جس کا اپنا نیٹ ورک نام اور پاس ورڈ ہوتا ہے۔

اس پروجیکٹ میں، AP کی ترتیبات اس طرح مقرر ہیں:


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

جب اسٹیشن موڈ ناکام ہو جاتا ہے، ماجیول AP موڈ میں تبدیل ہو جاتا ہے اور ESP32 نامی وائی فائی نیٹ ورک نشر کرنا شروع کر دیتا ہے۔ میٹرکس کو کنٹرول کرنے کے لیے:

  1. اپنے فون یا کمپیوٹر پر، وائی فائی کی ترتیبات کھولیں اور نیٹ ورک ESP32 سے منسلک ہوں۔
  2. پاس ورڈ password درج کریں (جیسا کہ کوڈ میں بیان کیا گیا ہے)۔
  3. منسلک ہونے کے بعد، ایک براؤزر کھولیں اور http://192.168.4.1/ پر جائیں (ESP32 AP موڈ کے لیے ڈیفالٹ IP)۔
  4. وہی کنٹرول صفحہ ظاہر ہوتا ہے، جس سے آپ متن، رنگ، رفتار، اور سمت تبدیل کر سکتے ہیں۔

یہ فال بیک رویہ پروجیکٹ کو کہیں بھی مفید بناتا ہے: گھر پر، لیب میں، یا ڈیمو ماحول میں جہاں کوئی روٹر دستیاب نہ ہو۔

پروجیکٹ 3 – کوڈ میں اہم ترتیبات

مکمل HTTP ٹیکسٹ اسکیچ اس مضمون کے نیچے ویب سائٹ کے ذریعے لوڈ کیا گیا ہے۔ یہاں ہم صرف سب سے اہم کنفیگریشن آپشنز دستاویز کرتے ہیں جنہیں آپ ممکنہ طور پر تبدیل کریں گے۔

وائی فائی اور ایکسیس پوائنٹ کی ترتیبات

اسکیچ کے اوپری حصے میں آپ کو وائی فائی کنفیگریشن سیکشن ملے گا۔ صرف اسٹیشن (گھر کے وائی فائی) کی اسناد تبدیل کریں؛ AP کی ترتیبات عام طور پر ڈیفالٹ رکھی جاتی ہیں:


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

// Home Wi-Fi (Station mode)
const char* WIFI_SSID = "YourHomeWiFi";      // put your router SSID here
const char* WIFI_PASS = "YourHomePassword";  // put your router password here

// Fallback Access Point (AP mode)
const char* AP_SSID = "ESP32";               // fixed AP name
const char* AP_PASS = "password";            // fixed AP password

رویہ:

  • اگر WIFI_SSID اور WIFI_PASS درست ہیں اور نیٹ ورک دستیاب ہے تو ESP32 ایک عام وائی فائی ڈیوائس (اسٹیشن موڈ) کے طور پر منسلک ہوتا ہے۔
  • اگر ٹائم آؤٹ کے بعد کنکشن ناکام ہو جاتا ہے تو ESP32 AP_SSID اور AP_PASS کا استعمال کرتے ہوئے اپنا AP شروع کرتا ہے۔

میٹرکس پن، سائز، اور چمک

یہ ترتیبات پچھلے پروجیکٹس کی طرح ہیں:


// Matrix configuration
const int MATRIX_PIN    = 14;   // RGB matrix data pin
const int MATRIX_WIDTH  = 8;
const int MATRIX_HEIGHT = 8;

// Overall display brightness (0–255)
uint8_t matrixBrightness = 40;  // adjust for your environment

اس بورڈ کے لیے MATRIX_PIN کو 14 پر رکھیں۔ اگر آپ کو زیادہ روشنی کی ضرورت ہو تو آپ matrixBrightness بڑھا سکتے ہیں، لیکن قریب سے دیکھنے کے لیے کم قدریں زیادہ آرام دہ ہیں۔

ڈیفالٹ متن اور اسکرول کی ترتیبات

جب بورڈ شروع ہوتا ہے، یہ ایک ابتدائی پیغام دکھاتا ہے جب تک کہ آپ ویب صفحہ کھول کر نیا متن ٹائپ نہ کریں۔ آپ کنفیگریشن میں ڈیفالٹ متن تبدیل کر سکتے ہیں:


// Default message shown at startup
String currentText = "Robojax";   // overwrite from web UI later

باقی اسکرول رویہ متغیرات کے ایک سیٹ سے کنٹرول ہوتا ہے جو ویب انٹرفیس کے ذریعے اپ ڈیٹ ہوتے ہیں:


// Scroll delay in milliseconds (lower = faster)
int scrollDelayMs = 50;

// Scroll direction: 0=left, 1=right, 2=up, 3=down
int scrollDirection = 0;   // default: scroll left

ویب صفحہ سلائیڈر اور بٹن کے انتخاب کی بنیاد پر نئی قدریں بھیجتا ہے۔ Arduino کی طرف سے، آپ کو صرف یہ جاننے کی ضرورت ہے کہ:

  • scrollDelayMs کم کرنے سے متن تیزی سے حرکت کرتا ہے۔
  • scrollDelayMs بڑھانے سے یہ آہستہ حرکت کرتا ہے۔
  • scrollDirection تبدیل کرنے سے بائیں، دائیں، اوپر، یا نیچے اسکرول موڈز کے درمیان سوئچ ہوتا ہے۔

متن کا رنگ (ویب صفحہ سے کنٹرول کیا جاتا ہے)

متن کا رنگ تین 0–255 اقدار (سرخ، سبز، نیلا) سے کنٹرول ہوتا ہے۔ جب بھی آپ ویب صفحہ پر نیا رنگ منتخب کرتے ہیں تو یہ اپ ڈیٹ ہوتے ہیں:


// Current text color (R, G, B)
uint8_t textRed   = 255;
uint8_t textGreen = 255;
uint8_t textBlue  = 255;

جب آپ براؤزر میں رنگ منتخب کرتے ہیں اور Apply پر کلک کرتے ہیں، ESP32 RGB اقدار کو پارس کرتا ہے اور ان تین متغیرات کو اپ ڈیٹ کرتا ہے؛ متن فوری طور پر میٹرکس پر رنگ بدل جاتا ہے۔ ویڈیو میں، یہ رویہ متعدد رنگ تبدیلیوں کے ساتھ دکھایا گیا ہے، بشمول سرخ، سبز اور نیلے رنگ کی مثالیں۔:contentReference[oaicite:5]{index=5}

خلاصہ

پروجیکٹ 3 آپ کے ESP32-S3 RGB LED میٹرکس کو ایک مکمل وائرلیس ٹیکسٹ ڈسپلے میں بدل دیتا ہے جسے آپ ویب براؤزر والے کسی بھی ڈیوائس سے کنٹرول کر سکتے ہیں۔ اسکیچ کو مضبوط بنانے کے لیے ڈیزائن کیا گیا ہے:

  • یہ پہلے آپ کے گھر کے وائی فائی سے جڑنے کی کوشش کرتا ہے جس میں آپ نے ترتیب دیا ہوا SSID اور پاس ورڈ استعمال ہوتا ہے۔
  • اگر یہ ناکام ہو جائے، تو یہ خود بخود ایک ایکسیس پوائنٹ بن جاتا ہے جس کا نام ESP32 اور پاس ورڈ password ہوتا ہے۔
  • دونوں طریقوں میں، براؤزر میں درست IP ایڈریس کھولنے سے متن، رنگ، سمت، اور رفتار کے لیے وہی کنٹرول صفحہ ظاہر ہوتا ہے۔

مکمل HTTP ٹیکسٹ کوڈ اس مضمون کے نیچے دستیاب ہے (ویب سائٹ پر خود بخود لوڈ ہوتا ہے)۔ مرحلہ وار مکمل رہنمائی اور متن کے حقیقی وقت میں اپ ڈیٹ ہونے کے لائیو مظاہرے کے لیے، ویڈیو کے پروجیکٹ 3 سیکشن کو ضرور دیکھیں۔ اگر آپ خود یہ پروجیکٹ بنانا چاہتے ہیں، تو آپ کوڈ کے نیچے دیے گئے ایفلی ایٹ لنکس کے ذریعے ESP32-S3 RGB LED میٹرکس ماجیول بھی خرید سکتے ہیں۔

تصاویر

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
زبان: 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();
  }
}

آپ کو جن چیزوں کی ضرورت ہو سکتی ہے

وسائل اور حوالہ جات

فائلیں📁

فریٹزنگ فائل