Morse Code & Message Sender
Use ESP32 to send messages with WiFi
Components and supplies
1
Active Buzzer
1
Arduino® Nano ESP32
1
Push Button
1
16x2 LCD display with I²C interface
1
Resistors
1
LED (generic)
Apps and platforms
1
Arduino IDE 2.0 (beta)
Project description
Code
Message sender
cpp
Here is the code I used. Html is used for webpage.
1#include <vector> 2#include <WiFi.h> 3#include <AsyncTCP.h> 4#include <ESPAsyncWebServer.h> 5#include <Wire.h> 6#include <hd44780.h> // lcd libraries 7#include <hd44780ioClass/hd44780_I2Cexp.h> 8 9hd44780_I2Cexp lcd; // Create lcd object (MUST be named "lcd") 10 11 12const char* ssid = "Your Network"; 13const char* password = "Your Password"; 14 15AsyncWebServer server(80); // port 80 = normal HTTP 16AsyncEventSource events("/events"); // Global SSE endpoint 17 18struct Message { 19 String text; 20 String mode; 21}; 22std::vector<Message> messageQueue; 23 24 25int buzzPin = 19; 26int LEDpin = 27; 27int bPin = 18; 28int bVal; 29 30char letter; 31bool space; 32bool messageSent = false; 33bool playMessage; 34void setup() { 35 // put your setup code here, to run once: 36 Serial.begin(115200); 37 Wire.begin(); 38 lcd.begin(16,2); 39 pinMode(buzzPin,OUTPUT); 40 pinMode(bPin,INPUT_PULLUP); 41 pinMode(LEDpin,OUTPUT); 42 43 44 WiFi.begin(ssid, password); 45 Serial.println("Connecting to Wi-Fi..."); 46 while (WiFi.status() != WL_CONNECTED) { 47 delay(500); 48 Serial.print("."); 49 } 50 Serial.println(); 51 Serial.print("Connected! IP address: "); 52 Serial.println(WiFi.localIP()); 53 server.addHandler(&events); 54 server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ 55 request->send(200, "text/html", R"rawliteral( 56 <!DOCTYPE html> 57 <html lang="en"> 58 <head> 59 <meta charset="UTF-8"> 60 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 61 <title>Message Sender</title> 62 <style> 63 body { font-family: sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; background: #f0f0f0;} 64 .container { background:white; padding:30px; border-radius:15px; max-width:500px; width:100%; text-align:center; box-shadow:0 10px 25px rgba(0,0,0,0.1);} 65 textarea { width:100%; padding:10px; font-size:16px; border-radius:8px; border:1px solid #ccc; margin-bottom:20px; resize:none;} 66 button { padding:12px 40px; font-size:16px; border:none; border-radius:50px; background: #667eea; color:white; cursor:pointer; transition:0.3s;} 67 button:hover { background:#764ba2;} 68 #status { display:none; margin-top:20px; padding:10px; background:#4CAF50; color:white; border-radius:8px; } 69 </style> 70 </head> 71 <body> 72 <div class="container"> 73 <h1>Message Sender</h1> 74 <textarea id="message-input" rows="3" placeholder="Type your message here..."></textarea> 75 <br> 76 <div class="mode-section"> 77 <label for="mode">Select Mode:</label> 78 <select id="mode"> 79 <option value="morse">Morse Encoder</option> 80 <option value="lcd">LCD Display</option> 81 </select> 82 </div> 83 <br> 84 <button onclick="sendMessage()">🚀 Send Message</button> 85 <div id="status">Message received!</div> 86 </div> 87 <script> 88 // Connect to SSE 89 const evtSource = new EventSource("/events"); 90 evtSource.onmessage = function(e) { 91 const statusDiv = document.getElementById("status"); 92 statusDiv.style.display = "block"; 93 statusDiv.innerText = e.data; 94 }; 95 96 function sendMessage() { 97 const statusDiv = document.getElementById("status"); 98 statusDiv.style.display = "none"; // hide immediately 99 100 const msg = document.getElementById("message-input").value; 101 const mode = document.getElementById("mode").value; 102 103 fetch(`/send?msg=${encodeURIComponent(msg)}&mode=${encodeURIComponent(mode)}`) 104 .then(response => response.text()) 105 .then(data => console.log(data)); 106 } 107 </script> 108 </body> 109 </html> 110 )rawliteral"); 111 }); 112 113 // Route to receive message & store to queue 114server.on("/send", HTTP_GET, [](AsyncWebServerRequest *request){ 115 if (request->hasParam("msg") && request->hasParam("mode")) { 116 String msg = request->getParam("msg")->value(); 117 String mode = request->getParam("mode")->value(); 118 119 // Save both message and mode into queue 120 Message newMessage; 121 newMessage.text = msg; 122 newMessage.mode = mode; 123 messageQueue.push_back(newMessage); 124 125 Serial.println("Queued: " + msg + " (mode: " + mode + ")"); 126 request->send(200, "text/plain", "Message queued!"); 127 } else { 128 request->send(400, "text/plain", "Missing message or mode"); 129 } 130}); 131 server.begin(); 132} 133 134void loop() { 135 // put your main code here, to run repeatedly: 136 137 if(!messageQueue.empty()){ 138 digitalWrite(LEDpin,HIGH); //led shows message waiting 139 lcd.setCursor(0,0); 140 lcd.print("message awaiting"); 141 bVal = digitalRead(bPin); 142 //wait for button to play message 143 if(bVal == 0){ 144 playMessage = true; 145 } 146 } 147 148 if(playMessage == true){ 149 digitalWrite(LEDpin,LOW); 150 Message nextMessage = messageQueue[0]; // get first message 151 messageQueue.erase(messageQueue.begin()); // remove it from queue 152 153 if(nextMessage.mode == "morse"){ 154 Serial.println("Playing message: " + nextMessage.text); 155 delay(100); // debounce 156 playMorse(nextMessage.text); 157 }else if (nextMessage.mode == "lcd"){ 158 Serial.println("Playing message: " + nextMessage.text); 159 delay(100); // debounce 160 lcd.clear(); 161 lcd.setCursor(0,0); 162 lcd.print(nextMessage.text); 163 } 164 165 166 167 events.send("Played message: " + nextMessage.text, "message", millis()); 168 playMessage = false; // reset playMessage 169 } 170 171 172 173} 174 175void dot(){ 176 digitalWrite(buzzPin,HIGH); 177 delay(200); 178 Serial.println("."); // 1 time unit 179 digitalWrite(buzzPin,LOW); 180 delay(200); // 3 times units of space 181} 182void dash(){ 183 digitalWrite(buzzPin,HIGH); 184 delay(600); 185 Serial.println("-"); 186 digitalWrite(buzzPin,LOW); 187 delay(200); // 3 time units space 188} 189void translate(char c){ 190 switch (c){ 191 case 'a' : dot(); dash(); break; 192 case 'b' : dash(); dot(); dot(); dot(); break; 193 case 'c' : dash(); dot(); dash(); dot(); break; 194 case 'd' : dash(); dot(); dot(); break; 195 case 'e' : dot(); break; 196 case 'f' : dot(); dot(); dash(); dot(); break; 197 case 'g' : dash(); dash(); dot(); break; 198 case 'h' : dot(); dot(); dot(); dot(); break; 199 case 'i' : dot(); dot(); break; 200 case 'j' : dot(); dash(); dash(); dash(); break; 201 case 'k' : dash(); dot(); dash(); break; 202 case 'l' : dot(); dash(); dot(); dot(); break; 203 case 'm' : dash(); dash(); break; 204 case 'n' : dash(); dot(); break; 205 case 'o' : dash(); dash(); dash(); break; 206 case 'p' : dot(); dash(); dash(); dot(); break; 207 case 'q' : dash(); dash(); dot(); dash(); break; 208 case 'r' : dot(); dash(); dot(); break; 209 case 's' : dot(); dot(); dot(); break; 210 case 't' : dash(); break; 211 case 'u' : dot(); dot(); dash(); break; 212 case 'v' : dot(); dot(); dot(); dash(); break; 213 case 'w' : dot(); dash(); dash(); break; 214 case 'x' : dash(); dot(); dot(); dash(); break; 215 case 'y' : dash(); dot(); dash(); dash(); break; 216 case 'z' : dash(); dash(); dot(); dot(); break; 217 case ' ' : space = true; break; 218 } 219 220} 221void playMorse(String message){ 222 for(int i = 0; i<message.length();i++){ 223 letter = message.charAt(i); 224 Serial.println(letter); 225 translate(letter); 226 delay(600); 227 if(space == true){ 228 delay(800); // 4 time units of space, + 3 units from earlier makes 7 units 229 space = false; 230 } 231 } 232}
Documentation
Web Page view
Here is what the webpage looks like
Screenshot 2025-09-28 173929.png

Comments
Only logged in users can leave comments