#include #include // WiFi and MQTT config const char* ssid = "SSID Name"; //Replace with your SSID const char* password = "SSID Password"; //Replace with your SSID Password const char* mqtt_server = "mqtt.fabcloud.org"; // or your own broker IP const int mqtt_port = 1883; const char* mqtt_user = "fabacademy"; // MQTT Credential Username const char* mqtt_pass = "fabacademy"; // MQTT Credential Password const char* deviceID = "device2"; //device name. You need different device names for each device const char* clientID = "esp32Client2" //change client ID. You need unique client IDs for each device WiFiClient clientID; PubSubClient client(clientID); // Pins const int buttonPin = D2; const int ledPin = D0; const int tonePin = D3; // Timing unsigned long t1, t2; int onTime; unsigned long gap; const int debounceDelay = 50; const int dotLength = 250; const int letterSpace = 600; const int wordSpace = 1400; const int toneFreq = 550; const int maxLineLength = 30; // Morse data String dashSeq = ""; bool newLetter = false; bool newWord = false; int lineLength = 0; char keyLetter; bool letterFound = false; int i; // Morse dictionary String letters[26] = { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.." }; String numbers[10] = { "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----." }; // Setup WiFi void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("WiFi connected. IP address: "); Serial.println(WiFi.localIP()); } // MQTT message received callback void callback(char* topic, byte* payload, unsigned int length) { String msg = ""; for (unsigned int i = 0; i < length; i++) { msg += (char)payload[i]; } // Ignore your own messages if (msg.startsWith(String(deviceID) + ":")) return; Serial.print("Received: "); Serial.println(msg); // Extract only the message content (after colon) int sepIndex = msg.indexOf(':'); if (sepIndex != -1) { String content = msg.substring(sepIndex + 1); playMorse(convertToMorse(content)); } } // Convert char to Morse String convertToMorse(String message) { String morseCode = ""; message.toUpperCase(); for (int i = 0; i < message.length(); i++) { char c = message.charAt(i); if (c == ' ') { morseCode += " "; // word gap } else if (c >= 'A' && c <= 'Z') { morseCode += letters[c - 'A'] + " "; } else if (c >= '0' && c <= '9') { morseCode += numbers[c - '0'] + " "; } } return morseCode; } // Play Morse on buzzer void playMorse(String morse) { for (int i = 0; i < morse.length(); i++) { char c = morse.charAt(i); if (c == '.') { tone(tonePin, toneFreq); delay(200); noTone(tonePin); } else if (c == '-') { tone(tonePin, toneFreq); delay(600); noTone(tonePin); } else if (c == ' ') { delay(400); // space between characters or words } delay(200); // symbol gap } } // MQTT reconnect void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); if (client.connect("esp32Client2", mqtt_user, mqtt_pass)) { Serial.println("connected"); client.subscribe("fabacademy/morse/topic"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5s"); delay(5000); } } } void setup() { pinMode(buttonPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT); pinMode(tonePin, OUTPUT); Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } void loop() { if (!client.connected()) reconnect(); client.loop(); // Button input: decode Morse if (digitalRead(buttonPin) == LOW) { newLetter = true; newWord = true; t1 = millis(); digitalWrite(ledPin, HIGH); tone(tonePin, toneFreq); delay(debounceDelay); while (digitalRead(buttonPin) == LOW) delay(debounceDelay); delay(debounceDelay); t2 = millis(); onTime = t2 - t1; digitalWrite(ledPin, LOW); noTone(tonePin); dashSeq += (onTime <= dotLength * 1.5) ? "." : "-"; } gap = millis() - t2; if (newLetter && gap >= letterSpace) { letterFound = false; keyLetter = '?'; for (i = 0; i <= 25; i++) { if (dashSeq == letters[i]) { keyLetter = i + 65; letterFound = true; break; } } if (!letterFound) { for (i = 0; i <= 9; i++) { if (dashSeq == numbers[i]) { keyLetter = i + 48; letterFound = true; break; } } } Serial.print(keyLetter); client.publish("fabacademy/morse/topic", (String(deviceID) + ":" + keyLetter).c_str()); if (!letterFound) tone(tonePin, 100, 500); newLetter = false; dashSeq = ""; lineLength++; } if (newWord && gap >= wordSpace * 1.5) { newWord = false; Serial.print("_"); client.publish("fabacademy/morse/topic", (String(deviceID) + ":_").c_str()); digitalWrite(ledPin, HIGH); delay(25); digitalWrite(ledPin, LOW); lineLength++; } if (lineLength >= maxLineLength) { Serial.println(); lineLength = 0; } }