QC

Morse code and message sender

Use ESP32 to send messages with WiFi

Devices and components

Arduino®Nano ESP32

16x2 LCD screen with I²C interface

Active buzzer

Push button

Resistors

LED (generic)

Software and tools

Arduino IDE

Project description

Message sender

Here is the code I used. HTML is used for the web page.

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}

Viewing the web page




Note: Content and images are from: https://projecthub.arduino.cc/, with some modifications.
If you want it removed due to copyright reasons, please leave a comment. Thank you.
I want to share this article more widely so that everyone knows about Arduino and your project.

Easy remote control

Remotely control an LED with ease. Devices and components Arduino Nano 33 BLE with headers Box 525 Resistors precision 1% - 17 values Breadb...