HOW-TO: MQTT to SMS Relay Service
HOW-TO: MQTT to SMS Relay Service
Section titled โHOW-TO: MQTT to SMS Relay ServiceโThis supplemental activity teaches students how to build a standalone program that listens to MQTT messages and relays them as SMS notifications via email-to-SMS gateways.
Learning Objectives
Section titled โLearning ObjectivesโBy completing this activity, students will understand:
- MQTT publish/subscribe pattern for event-driven systems
- Email-to-SMS gateway integration
- String parsing and topic extraction
- Real-time event notification
- Error handling in production services
Part 1: Complete Program
Section titled โPart 1: Complete ProgramโCreate mqtt_sms_relay.py
Section titled โCreate mqtt_sms_relay.pyโ#!/usr/bin/env python3"""MQTT to SMS Relay Service
Listens for messages on MQTT topic "SMS/+" and relays them as SMS notifications.Topic format: SMS/<subject>Payload: SMS message body
Example: Topic: SMS/Temperature Alert Payload: Temperature exceeded 35ยฐC in greenhouse
Result: SMS sent with subject "Temperature Alert" and message body"""
import smtplibimport paho.mqtt.client as mqttimport sysfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipart
# ============================================# CONFIGURATION - EDIT THESE VALUES# ============================================
# Email Account (Gmail recommended)SENDER_EMAIL = "your.email@gmail.com" # Gmail addressSENDER_PASSWORD = "xxxx xxxx xxxx xxxx" # Gmail App Password (NOT regular password)SMTP_SERVER = "smtp.gmail.com"SMTP_PORT = 587
# SMS ConfigurationALERT_NUMBER = "5145557777" # Phone number to receive SMSALERT_GATEWAY = "txt.bell.ca" # Carrier SMS gateway
# MQTT ConfigurationMQTT_BROKER = "localhost"MQTT_PORT = 1883MQTT_TOPIC = "SMS/+" # Subscribe to SMS/* topics
# ============================================# SMS SENDING FUNCTION# ============================================
def send_sms(message, subject=None): """ Send SMS via email-to-SMS gateway
Args: message (str): SMS message body subject (str): SMS subject (optional)
Returns: tuple: (success, response_message) """
# Construct SMS gateway email address sms_email = f"{ALERT_NUMBER}@{ALERT_GATEWAY}"
try: # Create MIME message msg = MIMEMultipart() msg['From'] = SENDER_EMAIL msg['To'] = sms_email msg['Subject'] = subject or "SMS Notification"
# Attach message body (SMS gateways usually ignore subject, use body) msg.attach(MIMEText(message, 'plain'))
# Connect to SMTP server and send server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT) server.starttls() # Encrypt connection server.login(SENDER_EMAIL, SENDER_PASSWORD) server.send_message(msg) server.quit()
return True, f"SMS sent to {sms_email}"
except smtplib.SMTPAuthenticationError: return False, "Gmail login failed - check SENDER_EMAIL and SENDER_PASSWORD" except smtplib.SMTPException as e: return False, f"SMTP error: {e}" except Exception as e: return False, f"Error: {e}"
# ============================================# MQTT CALLBACKS# ============================================
def on_connect(client, userdata, flags, rc): """Called when MQTT client connects to broker""" if rc == 0: print(f"โ Connected to MQTT broker") print(f"Subscribing to topic: {MQTT_TOPIC}") client.subscribe(MQTT_TOPIC) else: print(f"โ Connection failed with code {rc}") sys.exit(1)
def on_message(client, userdata, msg): """Called when message received on subscribed topic"""
# Extract SMS subject from topic # Topic format: SMS/<subject> # msg.topic example: "SMS/Temperature Alert"
# Split topic by "/" to extract subject topic_parts = msg.topic.split("/")
if len(topic_parts) >= 2: # Everything after "SMS/" is the subject subject = "/".join(topic_parts[1:]) else: subject = "IoT Alert"
# Get message payload try: message = msg.payload.decode("utf-8") except UnicodeDecodeError: message = str(msg.payload)
# Log received message print(f"\n=== SMS Relay Triggered ===") print(f"Topic: {msg.topic}") print(f"Subject: {subject}") print(f"Message: {message}")
# Send SMS print(f"Sending SMS...") success, response = send_sms(message, subject)
if success: print(f"โ {response}\n") else: print(f"โ {response}\n")
def on_disconnect(client, userdata, rc): """Called when MQTT client disconnects""" if rc != 0: print(f"โ Unexpected MQTT disconnection") else: print(f"Disconnected from MQTT broker")
# ============================================# MAIN PROGRAM# ============================================
def main(): """Main relay service"""
print(f"\n{'='*50}") print(f"MQTT to SMS Relay Service") print(f"{'='*50}\n")
# Verify configuration print(f"Configuration:") print(f" MQTT Broker: {MQTT_BROKER}:{MQTT_PORT}") print(f" Topic Filter: {MQTT_TOPIC}") print(f" Alert Number: {ALERT_NUMBER}") print(f" SMS Gateway: {ALERT_GATEWAY}") print(f" Sender Email: {SENDER_EMAIL}\n")
# Create MQTT client client = mqtt.Client(client_id="mqtt-sms-relay") client.on_connect = on_connect client.on_message = on_message client.on_disconnect = on_disconnect
# Connect to broker try: print(f"Connecting to MQTT broker...") client.connect(MQTT_BROKER, MQTT_PORT, 60) except Exception as e: print(f"โ Failed to connect to MQTT broker: {e}") print(f"Check that Mosquitto is running: sudo systemctl status mosquitto") sys.exit(1)
# Start listening print(f"โ Ready to relay SMS messages") print(f"Waiting for messages...") print(f"(Press Ctrl+C to stop)\n")
try: client.loop_forever() except KeyboardInterrupt: print(f"\nShutting down...") client.disconnect() sys.exit(0)
if __name__ == "__main__": main()Detailed Explanation:
Section titled โDetailed Explanation:โTopic Parsing:
topic_parts = msg.topic.split("/")subject = "/".join(topic_parts[1:])- Split topic by โ/โ:
"SMS/Temperature Alert"โ["SMS", "Temperature Alert"] - Extract subject: Everything after โSMS/โ becomes SMS subject
"/".join()re-joins if subject contains slashes:SMS/House/TempโHouse/Temp
MQTT Callbacks:
on_connect(): Runs when connected, subscribes to topic filteron_message(): Runs when message arrives, triggers SMS sendon_disconnect(): Runs when disconnected
Payload Decoding:
message = msg.payload.decode("utf-8")- MQTT payload arrives as bytes
- Decode to string for SMS message
Error Handling:
- Catches SMTP authentication errors (wrong password)
- Catches connection errors (MQTT broker offline)
- Provides helpful error messages
Part 2: Setup Instructions
Section titled โPart 2: Setup InstructionsโStep 1: Configure Email Credentials
Section titled โStep 1: Configure Email CredentialsโEdit mqtt_sms_relay.py and update:
SENDER_EMAIL = "your.email@gmail.com"SENDER_PASSWORD = "xxxx xxxx xxxx xxxx" # Gmail App PasswordALERT_NUMBER = "5145557777"ALERT_GATEWAY = "txt.bell.ca" # Your carrier's gatewayHow to get Gmail App Password:
- Go to https://myaccount.google.com โ
- Click โSecurityโ (left menu)
- Enable 2-Factor Authentication if not done
- Go to https://myaccount.google.com/apppasswords โ
- Select โMailโ and โLinux/Windows/Macโ
- Google generates 16-character password
- Copy it (includes spaces:
xxxx xxxx xxxx xxxx)
Carrier gateways: See https://www.textmagic.com/blog/email-to-text-service/ โ
Step 2: Start the Relay
Section titled โStep 2: Start the Relayโpython3 mqtt_sms_relay.pyExpected output:
==================================================MQTT to SMS Relay Service==================================================
Configuration: MQTT Broker: localhost:1883 Topic Filter: SMS/+ Alert Number: 5145557777 SMS Gateway: txt.bell.ca Sender Email: your.email@gmail.com
Connecting to MQTT broker...โ Connected to MQTT brokerโ Subscribing to topic: SMS/+โ Ready to relay SMS messagesWaiting for messages...(Press Ctrl+C to stop)Part 3: Testing
Section titled โPart 3: TestingโTest 1: Manual MQTT Publish
Section titled โTest 1: Manual MQTT PublishโFrom another terminal:
# Publish a test SMSmosquitto_pub -t "SMS/Test Alert" -m "This is a test SMS message"Relay service output:
=== SMS Relay Triggered ===Topic: SMS/Test AlertSubject: Test AlertMessage: This is a test SMS messageSending SMS...โ SMS sent to 5145557777@txt.bell.caTest 2: Multiple Subjects
Section titled โTest 2: Multiple Subjectsโmosquitto_pub -t "SMS/High Temperature" -m "Greenhouse temp is 45ยฐC!"mosquitto_pub -t "SMS/Low Humidity" -m "Humidity dropped to 20%"mosquitto_pub -t "SMS/Motion Alert" -m "Motion detected in lab"Each triggers a separate SMS.
Test 3: Nested Topics
Section titled โTest 3: Nested Topicsโ# Topic with multiple levelsmosquitto_pub -t "SMS/House/Temperature/Alert" -m "Temp too high"
# Subject becomes: "House/Temperature/Alert"Test 4: From IoT Controller
Section titled โTest 4: From IoT ControllerโModify your iot_controller.py to publish SMS alerts:
# When a rule triggersif conditions_met: action = rule.get("action")
# Publish to MQTT normally client.publish(action["topic"], action["value"])
# ALSO publish SMS alert sms_subject = f"Alert: {action['message']}" sms_topic = f"SMS/{sms_subject}" client.publish(sms_topic, action['message'])Part 4: Integration with IoT System
Section titled โPart 4: Integration with IoT SystemโAdd to iot_controller.py
Section titled โAdd to iot_controller.pyโWhen a rule triggers:
@staticmethoddef on_message(client, userdata, message): """Handle incoming MQTT messages and evaluate rules"""
# ... existing rule evaluation code ...
if conditions_met: action = rule.get("action")
# Original action (publish to MQTT) client.publish(action["topic"], action["value"]) print(f"ACTION: {action['message']}")
# NEW: Send SMS alert via relay service sms_subject = action['message'] # Use action message as SMS subject sms_topic = f"SMS/{sms_subject}"
# Publish to SMS relay (will be picked up and sent as SMS) client.publish(sms_topic, f"Alert triggered: {action['message']}") print(f"SMS Alert sent to relay")Part 5: Real-World Example Workflow
Section titled โPart 5: Real-World Example WorkflowโScenario: Temperature Alert System
Section titled โScenario: Temperature Alert Systemโ1. Publish sensor data:
mosquitto_pub -t "house/greenhouse/temperature" -m "38"2. IoT Controller evaluates rules:
- Rule: IF house/greenhouse/temperature > 35 THEN trigger alert
3. Controller publishes action:
# Original actionclient.publish("house/ac/command", "on")
# SMS notificationclient.publish("SMS/Greenhouse Temperature High", "Temperature 38ยฐC, AC turned on")4. MQTT SMS Relay receives SMS topic:
- Extracts subject: โGreenhouse Temperature Highโ
- Gets message: โTemperature 38ยฐC, AC turned onโ
- Sends SMS to alert number
5. Admin receives SMS:
Subject: Greenhouse Temperature HighMessage: Temperature 38ยฐC, AC turned onPart 6: Architecture Diagram
Section titled โPart 6: Architecture Diagramโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ IoT Sensor/Controller โโ (Publishes to MQTT when rule triggers) โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ Publishes to: โ SMS/Subject/Name โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ MQTT Broker โ โ (Mosquitto) โ โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ โ โ Subscribes to SMS/+ โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ MQTT SMS Relay Service โ <-- This program โ (mqtt_sms_relay.py) โ โ - Receives message โ โ - Extracts subject โ โ - Sends via SMTP โ โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ โ โ Sends email to: โ 5145557777@txt.bell.ca โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Gmail SMTP Server โ โ (smtp.gmail.com:587) โ โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ โ โ Forwards to: โ Carrier SMS Gateway โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Bell SMS Gateway โ โ (txt.bell.ca) โ โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ โ โ Converts to SMS โ โผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ Mobile Phone โ โ "Greenhouse Temp High" โ โ "Temperature 38ยฐC, ..." โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโPart 7: Error Handling
Section titled โPart 7: Error HandlingโCommon Issues and Solutions
Section titled โCommon Issues and SolutionsโIssue: โGmail login failedโ
Error: Gmail login failed - check SENDER_EMAIL and SENDER_PASSWORDSolutions:
- Verify Gmail address is correct
- Generate new App Password from myaccount.google.com/apppasswords
- Ensure 2-Factor Authentication is enabled
- Copy full 16-character password (including spaces)
Issue: โFailed to connect to MQTT brokerโ
Error: Failed to connect to MQTT brokerCheck that Mosquitto is running: sudo systemctl status mosquittoSolution:
sudo systemctl start mosquittoIssue: No SMS received
โ SMS sent to 5145557777@txt.bell.ca (but no SMS arrives)Solutions:
- Verify carrier SMS gateway is correct
- Phone number format must be 10 digits (no formatting)
- Check email account has SMTP access enabled
- Try a different carrier gateway from the reference list
Summary
Section titled โSummaryโYouโve built a production-ready MQTT to SMS relay that:
- Listens to MQTT topics with wildcard subscription
- Extracts subjects from topic path
- Sends SMS notifications via email-to-SMS gateways
- Integrates with IoT Controller for automated alerting
- Error handling for network and authentication issues
- Colored output for easy monitoring
- Completely free - uses Gmail and carrier gateways
Real-world applications:
- Alert system operators to equipment failures
- Send notifications when thresholds exceeded
- Emergency alerts to on-call staff
- IoT system status updates