This tutorial is part of: ESP32-S3 RGB LED ማትሪክስ
አስደሳች እና ተግባራዊ አፕሊኬሽኖችን ለመፍጠር የESP32-S3 RGB ማትሪክስ ሞጁልን በመጠቀም አሪፍ ፕሮጀክት። ወደ ሌሎች ቪዲዮዎች የሚወስዱ አገናኞች ከዚህ ጽሑፍ በታች ይገኛሉ።
የESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 3 - ከሞባይል ስልክ የሚመጣ ጽሑፍ
ፕሮጀክት 3 – ጽሑፍን ከስልክዎ ይቆጣጠሩ (ኤችቲቲፒ ጽሑፍ)
በዚህ ፕሮጀክት ውስጥ ESP32-S3 RGB LED ማትሪክስ ትንሽ የድር ገጽ ያስተናግዳል ስለዚህ የሚንቀሳቀሰውን ጽሑፍ፣ ቀለም፣ አቅጣጫ እና ፍጥነት በቀጥታ ከስልክዎ ወይም ከኮምፒውተርዎ መቀየር ይችላሉ። የተለየ መተግበሪያ አያስፈልግዎትም – የድር አሳሽ ብቻ ያስፈልጋል። ይህ ሞጁሉን በእውነተኛ ጊዜ ማዘመን የሚችሉት ትንሽ የWi-Fi ጽሑፍ ማሳያ ያደርገዋል።
በዚህ ተከታታይ ውስጥ ያሉት ስድስቱም ፕሮጀክቶች በአንድ የYouTube ቪዲዮ ተብራርተው ተቀርፀዋል። ተመሳሳዩ ቪዲዮ በዚህ ገጽ ላይ ተካቷል፣ ስለዚህ የድር በይነገጹ እንዴት እንደሚመስል እና ጽሑፍ በማትሪክስ ላይ ወዲያውኑ እንዴት እንደሚዘመን በትክክል ማየት ይችላሉ። ለዚህ ፕሮጀክት ሙሉ የምንጭ ኮድ ከጽሑፉ በታች በራስ-ሰር ተጭኗል፣ እና የESP32-S3 RGB LED ማትሪክስ ሞጁሉን በኮድ ክፍሉ ስር ከተዘረዘሩት የተባባሪ መደብሮች መግዛት ይችላሉ።
በዚህ ጽሑፍ ውስጥ የአውታረ መረብ አመክንዮ እንዴት እንደሚሰራ (የቤት Wi-Fi ከመዳረሻ ነጥብ ጋር) እና ባህሪውን ለማበጀት በኮዱ ውስጥ የትኞቹን ቅንብሮች መቀየር እንደሚችሉ ላይ እናተኩራለን።



የESP32-S3 RGB LED ማትሪክስ ሞጁል አጠቃላይ እይታ
ሃርድዌሩ በዚህ ተከታታይ ውስጥ ካሉት ሌሎች ፕሮጀክቶች ሁሉ ጋር ተመሳሳይ ነው፡ ከተሰራ ውስጡ 8×8 RGB LED ማትሪክስ እና በጀርባው ላይ QMI8658C የእንቅስቃሴ ዳሳሽ ያለው የESP32-S3 ማይክሮ መቆጣጠሪያ ሰሌዳ። የUSB-C ወደብ ለኃይል እና ለፕሮግራም አወጣጥ ጥቅም ላይ ይውላል፣ እና በጠርዙ ዙሪያ ያሉ ፒኖች ለሌላ IO አሁንም ይገኛሉ።:contentReference[oaicite:0]{index=0}

- ESP32-S3 – Wi-Fi እና ብሉቱዝ አቅም ያለው ማይክሮ መቆጣጠሪያ።
- 8×8 RGB ማትሪክስ – ለጽሑፍ እና ለግራፊክስ 64 አድራሻ ሊሰጣቸው የሚችሉ RGB LEDs።
- QMI8658C አክስሌሮሜትር – በማዘንበል እና በጨዋታ ፕሮጀክቶች ውስጥ ጥቅም ላይ ይውላል።
- USB ወደብ – ሰሌዳውን ያበረታታል እና ከArduino IDE ስኬቾችን ይሰቅላል።
- የተጋለጡ ፒኖች – አስፈላጊ ከሆነ ተጨማሪ ዳሳሾችን ወይም አንቀሳቃሾችን ይፈቅዳሉ።
- Boot/Reset አዝራሮች – ለፈርምዌር ሰቀላ እና እንደገና ለማስጀመር።
ለፕሮጀክት 3፣ በጣም አስፈላጊው ባህሪ የESP32 Wi-Fi ነው፣ ይህም ሰሌዳው ለጽሑፍ መቆጣጠሪያ ገጹ እንደ ትንሽ የድር አገልጋይ እንዲሰራ ያስችለዋል።:contentReference[oaicite:1]{index=1}

በቪዲዮው ውስጥ የተካተቱ ፕሮጀክቶች (የጊዜ ምልክቶች)
ለዚህ ተከታታይ አንዱ ቪዲዮ ስድስቱንም ፕሮጀክቶች ይሸፍናል። ለፈጣን ማጣቀሻ፡
- 00:00 – መግቢያ
- 02:01 – የESP32 ሰሌዳዎችን መጫን
- 03:32 – ቤተ-መጻሕፍትን መጫን
- 05:32 – ፕሮጀክት 1፡ የሚንቀሳቀስ ነጥብ
- 11:11 – ፕሮጀክት 2፡ የጽሑፍ ማንሸራተት
- 12:59 – ፕሮጀክት 3፡ ኤችቲቲፒ ጽሑፍ (ይህ ፕሮጀክት)
- 16:41 – ፕሮጀክት 4፡ የማዘንበል ነጥብ
- 18:55 – ፕሮጀክት 5፡ ወደ ላይ ቀስት
- 20:02 – ፕሮጀክት 6፡ ዒላማ ጨዋታ
ከዚህ ጽሑፍ ጋር በመስራት ጊዜ በቪዲዮው ውስጥ ያለውን የኤችቲቲፒ ጽሑፍ ክፍል እንዲመለከቱ ይበረታታሉ። ቪዲዮው የድር ገጹ በESP32 እንዴት እንደሚፈጠር እና ጽሑፍን፣ ቀለምን እና ፍጥነትን መቀየር በLED ማትሪክስ ላይ ወዲያውኑ እንዴት እንደሚንጸባረቅ ያሳያል።:contentReference[oaicite:2]{index=2}
በArduino IDE ውስጥ የESP32 ሰሌዳዎችን መጫን
ፕሮጀክት 1 ወይም 2 አስቀድመው ካጠናቀቁ፣ የሰሌዳ ማዋቀሩ ተጠናቋል እና ይህን ክፍል መዝለል ይችላሉ። አለበለዚያ፣ በArduino IDE ውስጥ እነዚህን ደረጃዎች ይከተሉ፡
ፋይል > ምርጫዎችን ይክፈቱ እና የESP32 ሰሌዳዎችን URL ወደ “ተጨማሪ የሰሌዳ አስተዳዳሪ URLs” ያክሉ።- ወደ
መሳሪያዎች > ሰሌዳ > የሰሌዳ አስተዳዳሪ…ይሂዱ፣ESP32ን ይፈልጉ እና ኦፊሴላዊውን የESP32 ጥቅል ይጫኑ። - ትክክለኛውን የESP32-S3 RGB ማትሪክስ ሰሌዳ ከ
መሳሪያዎች > ሰሌዳይምረጡ። - ሞጁሉን በUSB ያገናኙ እና በ
መሳሪያዎች > ወደብስር ትክክለኛውን ተከታታይ ወደብ ይምረጡ።
ትክክለኛ የESP32 ሰሌዳ ድጋፍ እና ትክክለኛ ወደብ ከሌለ፣ የድር አገልጋይ ስኬቹ አይሰቀልም።
NeoMatrix እና አስፈላጊ ቤተ-መጻሕፍትን መጫን
ይህ ፕሮጀክት ከቀዳሚው የጽሑፍ ማንሸራተት ፕሮጀክት ጋር ተመሳሳይ ቤተ-መጻሕፍትን ይጠቀማል፡
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFX Library
በቤተ-መጻሕፍት አስተዳዳሪ በኩል ይጫኑ፡
ስኬች > ቤተ-መጻሕፍትን አካትት > ቤተ-መጻሕፍትን ያስተዳድሩ…ን ይክፈቱ።Adafruit NeoMatrixን ይፈልጉ እና ጫን ን ጠቅ ያድርጉ።- የጥገኞችን መጫን ይቀበሉ (
Adafruit GFXእናAdafruit NeoPixel)።
አንዴ ከተጫኑ በኋላ፣ በፋይል > ምሳሌዎች ስር የNeoMatrix እና NeoPixel ምሳሌ ስኬቾችን ማየት ይችላሉ።
በፕሮጀክት 3 ውስጥ ሁለት የWi-Fi ሁነታዎች
በዚህ ፕሮጀክት ውስጥ በጣም አስፈላጊው ጽንሰ-ሐሳብ ESP32 በሁለት የተለያዩ ሁነታዎች መስራት ይችላል የሚለው ነው፡
- ስቴሽን (STA) ሁነታ – ESP32 ከቤትዎ ካለው የWi-Fi አውታረ መረብ ጋር ይገናኛል።
- የመዳረሻ ነጥብ (AP) ሁነታ – የቤት Wi-Fi ከሌለ ESP32 የራሱን የWi-Fi አውታረ መረብ ይፈጥራል።
ሁለቱም ሁነታዎች ተመሳሳይ የድር በይነገጽ ይጠቀማሉ፡ ከESP32 ራሱ የሚቀርብ የኤችቲኤምኤል ገጽ፣ ጽሑፉን፣ ቀለሙን፣ የማንሸራተት አቅጣጫውን እና ፍጥነቱን መቀየር የሚችሉበት።:contentReference[oaicite:3]{index=3}
ሁነታ 1 – ከቤት Wi-Fi ጋር መገናኘት (ስቴሽን ሁነታ)
በስቴሽን ሁነታ፣ ESP32 ከቤትዎ ወይም ከቢሮዎ የWi-Fi አውታረ መረብ ጋር ይቀላቀላል። ራውተርዎ በሚገኝበት ጊዜ ይህ ተመራጭ ሁነታ ነው ምክንያቱም፡
- ስልክዎ እና ኮምፒውተርዎ ቀድሞውኑ ከተመሳሳይ የWi-Fi አውታረ መረብ ጋር የተገናኙ ናቸው።
- አሳሽዎን ወደ ESP32 የIP አድራሻ እየጠቆሙ በዚያ አውታረ መረብ ላይ ካሉ ማንኛውም መሣሪያ ጽሑፉን መቆጣጠር ይችላሉ።
በስኬቹ ቅንብሮች ክፍል ውስጥ፣ የWi-Fi SSID እና የይለፍ ቃልዎን ያቀርባሉ፡
// የቤት ዋይ-ፋይ ማረጋገጫዎች (Station ሁነታ) const char* WIFI_SSID = "YourHomeWiFi"; const char* WIFI_PASS = "YourHomePassword";ቦርዱ ከተነሳ በኋላ፣ WIFI_SSID ን ለመገናኘት ይሞክራል። ከተሳካ፣ ኮዱ የተመደበውን IP አድራሻ ወደ Serial Monitor ያትማል፣ ለምሳሌ፦
Connected to WiFi
IP address: 192.168.1.16
ጽሑፉን ለመቆጣጠር፦
- ስልክዎ ወይም ኮምፒውተርዎ ከተመሳሳይ ዋይ-ፋይ አውታረ መረብ ጋር መገናኘቱን ያረጋግጡ (ለምሳሌ፣
YourHomeWiFi)። - አሳሽ ይክፈቱ እና የታተመውን IP አድራሻ ያስገቡ፣ ለምሳሌ
http://192.168.1.16/። - የመቆጣጠሪያ ገጹ ይታያል፣ ጽሑፍ ለመተየብ፣ ቀለም ለመምረጥ፣ አቅጣጫ ለመምረጥ እና የማሸብለል ፍጥነትን ለማስተካከል ያስችልዎታል።
ሁነታ 2 – ገለልተኛ መዳረሻ ነጥብ (AP ሁነታ)
ESP32 ከቤትዎ ዋይ-ፋይ ጋር መገናኘት ካልቻለ (የተሳሳተ የይለፍ ቃል፣ አውታረ መረብ ካልተገኘ፣ ወይም ሞጁሉን ከቤት ውጭ እየተጠቀሙ ከሆነ)፣ ስኬቹ በራስ-ሰር ወደ መዳረሻ ነጥብ ሁነታ ይመለሳል። በAP ሁነታ፣ ESP32 ራሱ የራሱ የአውታረ መረብ ስም እና የይለፍ ቃል ያለው የዋይ-ፋይ መገናኛ ነጥብ ይሆናል።
በዚህ ፕሮጀክት ውስጥ፣ የAP ቅንብሮች እንደሚከተለው ተስተካክለዋል፦
// Access Point (AP) credentials (fallback mode)
const char* AP_SSID = "ESP32";
const char* AP_PASS = "password";
የStation ሁነታ ሲወድቅ፣ ሞጁሉ ወደ AP ሁነታ ይቀየራል እና ESP32 የሚባል የዋይ-ፋይ አውታረ መረብ ማሰራጨት ይጀምራል። ማትሪክሱን ለመቆጣጠር፦
- በስልክዎ ወይም በኮምፒውተርዎ ላይ፣ የዋይ-ፋይ ቅንብሮችን ይክፈቱ እና ከESP32 አውታረ መረብ ጋር ይገናኙ።
- የይለፍ ቃሉን password ያስገቡ (በኮዱ ውስጥ እንደተገለጸው)።
- ከተገናኙ በኋላ፣ አሳሽ ይክፈቱ እና ወደ
http://192.168.4.1/ይሂዱ (ለESP32 AP ሁነታ ነባሪ IP)። - ተመሳሳይ የመቆጣጠሪያ ገጽ ይታያል፣ ጽሑፍን፣ ቀለምን፣ ፍጥነትን እና አቅጣጫን ለመቀየር ያስችልዎታል።
ይህ የመጠባበቂያ ባህሪ ፕሮጀክቱን በማንኛውም ቦታ ጠቃሚ ያደርገዋል፦ በቤት፣ በላብራቶሪ፣ ወይም ራውተር በሌለበት የማሳያ አካባቢ።
ፕሮጀክት 3 – በኮዱ ውስጥ ዋና ቅንብሮች
ሙሉው የHTTP ጽሑፍ ስኬች ከዚህ ጽሑፍ በታች በድረ-ገጹ ተጭኗል። እዚህ ሊያርትዑት የሚችሉትን በጣም አስፈላጊ የውቅር አማራጮችን ብቻ እንመዘግባለን።
የዋይ-ፋይ እና የመዳረሻ ነጥብ ቅንብሮች
በስኬቹ አናት ላይ የዋይ-ፋይ ውቅር ክፍል ያገኛሉ። የStation (የቤት ዋይ-ፋይ) ማረጋገጫዎችን ብቻ ይቀይሩ፤ የ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 እንደ መደበኛ የዋይ-ፋይ መሣሪያ ይገናኛል (Station ሁነታ)።- ግንኙነቱ ከተወሰነ ጊዜ በኋላ ከተሳካ → ESP32 የራሱን AP በ
AP_SSIDእናAP_PASSይጀምራል።
የማትሪክስ ፒን፣ መጠን እና ብሩህነት
እነዚህ ቅንብሮች ከቀዳሚዎቹ ፕሮጀክቶች ጋር ተመሳሳይ ናቸው፦
// 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
የድረ-ገጹ ገጽ በስላይደር እና በአዝራር ምርጫዎች ላይ በመመስረት አዲስ እሴቶችን ይልካል። ከአርዱኢኖ ጎን፣ ማወቅ ያለብዎት ብቻ፦
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 እሴቶችን ይተነትናል እና እነዚህን ሦስት ተለዋዋጮች ያዘምናል፤ ጽሑፉ ወዲያውኑ በማትሪክሱ ላይ ቀለሙን ይቀይራል። በቪዲዮው ውስጥ፣ ይህ ባህሪ በበርካታ የቀለም ለውጦች፣ ቀይ፣ አረንጓዴ እና ሰማያዊ ምሳሌዎችን ጨምሮ ይታያል።
ማጠቃለያ
ፕሮጀክት 3 የእርስዎን ESP32-S3 RGB LED ማትሪክስ ሙሉ በሙሉ ገመድ አልባ የጽሑፍ ማሳያ ያደርገዋል፣ የድር አሳሽ ባለው ማንኛውም መሣሪያ መቆጣጠር ይችላሉ። ስኬቹ ጠንካራ እንዲሆን የተነደፈ ነው፦
- በመጀመሪያ የቤትዎን ዋይ-ፋይ በገቡት SSID እና የይለፍ ቃል ለመገናኘት ይሞክራል።
- ያ ካልተሳካ፣ በራስ-ሰር
ESP32በሚል ስም እናpasswordበሚል የይለፍ ቃል የመዳረሻ ነጥብ ይሆናል። - በሁለቱም ሁነታዎች፣ ትክክለኛውን IP አድራሻ በአሳሽ ውስጥ መክፈት ለጽሑፍ፣ ለቀለም፣ ለአቅጣጫ እና ለፍጥነት ተመሳሳይ የቁጥጥር ገጽ ያሳያል።
ሙሉው የHTTP ጽሑፍ ኮድ ከዚህ ጽሑፍ በታች ይገኛል (በድረ-ገጹ ላይ በራስ-ሰር ይጫናል)። ለተሟላ የደረጃ-በ-ደረጃ ማብራሪያ እና ጽሑፉ በእውነተኛ ጊዜ እንዴት እንደሚዘመን የቀጥታ ማሳያ፣ የቪዲዮውን የፕሮጀክት 3 ክፍል መመልከትዎን ያረጋግጡ። ፕሮጀክቱን እራስዎ መገንባት ከፈለጉ፣ ከኮዱ በታች በተዘረዘሩት የተባባሪ አገናኞች የESP32-S3 RGB LED Matrix ሞጁሉን መግዛት ይችላሉ።
This tutorial is part of: ESP32-S3 RGB LED ማትሪክስ
- ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 1- መሰረታዊ ነጥብ
- የESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 2 - የሚንቀሳቀስ ጽሑፍ
- ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 4 - ዘንበል ነጥብ
- ESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 5 - ቀስት ሁልጊዜ ወደ ላይ
- የESP32-S3 RGB LED ማትሪክስ ፕሮጀክት 6 - ሲብል ጨዋታ
- ESP32-S3 RGB LED ማትሪክስ ዋይ-ፋይ + NTP የሰዓት ፕሮጀክት -1 መሰረታዊ ሰዓት
- የESP32-S3 RGB LED ማትሪክስ የበይነመረብ ሰዓት ፕሮጀክት - 2 ሰዓት ባለብዙ ቀለም ጊዜ እና ቀን ማሳያ
- የESP32-S3 RGB LED ማትሪክስ የበይነመረብ ሰዓት ፕሮጀክት - 3 የምሽት ቀለም ከቀን ጋር
- የESP32-S3 RGB LED ማትሪክስ የበይነመረብ ሰዓት ፕሮጀክት - 5 የቀስተ ደመና ቀለም
- የESP32-S3 RGB LED ማትሪክስ የበይነመረብ ሰዓት ፕሮጀክት - 4 የዘፈቀደ ቀለም
- ESP32-S3 RGB LED Matrix test for RGB, GRB setting
/*
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')">▲</button>
<div></div>
<button class="arrow-btn" id="btnLeft" onclick="setDir('left')">◀</button>
<div></div>
<button class="arrow-btn" id="btnRight" onclick="setDir('right')">▶</button>
<div></div>
<button class="arrow-btn" id="btnDown" onclick="setDir('down')">▼</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();
}
}
እንደሚያስፈልግዎት ይችላል
-
አማዞን
-
ኢቤይ
-
አሊኤክስፕሬስPurchase ESP32-S3 RGB Matrix from AliExpresss.click.aliexpress.com
-
አሊኤክስፕሬስPurchase ESP32-S3 RGB Matrix from AliExpress (2)s.click.aliexpress.com
ምንጮች እና ምንጮች
-
ውስጥ🎨 Color picker Toolrobojax.com
ፋይሎች📁
ፍሪትዚንግ ፋይል
-
esp32-S3-supermini-tht fritzing part
esp32-S3-supermini-tht.fzpz0.02 MB