diff --git a/tools/webapp/app.py b/tools/webapp/app.py new file mode 100644 index 0000000000000000000000000000000000000000..07f57f57ed6d1fd5330a16d3cff3be3aa93f60c8 --- /dev/null +++ b/tools/webapp/app.py @@ -0,0 +1,60 @@ +from flask import Flask, render_template, request, jsonify +import paho.mqtt.client as mqtt + +# Flask app initialization +app = Flask(__name__) + +# MQTT Configuration +BROKER = "localhost" # Replace with your broker +PUBLISH_TOPIC = "colors/publish" +LOG_TOPIC = "colors/log" + +mqtt_client = mqtt.Client() + +# On connect, subscribe to the log topic +def on_connect(client, userdata, flags, rc): + print(f"Connected to MQTT Broker with result code {rc}") + mqtt_client.subscribe(LOG_TOPIC) + +# On receiving a message, print it +log_messages = [] + +def on_message(client, userdata, msg): + global log_messages + message = msg.payload.decode() + log_messages.append(message) + +# Assign MQTT event handlers +mqtt_client.on_connect = on_connect +mqtt_client.on_message = on_message + +# Connect to the broker +mqtt_client.connect(BROKER, 1884, 60) +mqtt_client.loop_start() + +# Route for the main page +@app.route('/') +def index(): + # List of colors to display as buttons + colors = ["red", "blue", "green"] + return render_template('index.html', colors=colors) + +# Route to handle button press +@app.route('/publish', methods=['POST']) +def publish(): + color = request.json.get("color") + if color: + topic = f"/{color}" # Each color gets its own topic + mqtt_client.publish(topic, color) + return jsonify({"status": "success", "topic": topic, "color": color}) + return jsonify({"status": "error"}), 400 + + +# Route to fetch log messages +@app.route('/logs', methods=['GET']) +def get_logs(): + return jsonify(log_messages) + +if __name__ == '__main__': + app.run(debug=True) + diff --git a/tools/webapp/templates/index.html b/tools/webapp/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..758137128e02b81faefdbd27654a9e9d37febefb --- /dev/null +++ b/tools/webapp/templates/index.html @@ -0,0 +1,139 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Selector</title> + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet"> + <style> + body { + font-family: 'Inter', sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f9; + color: #333; + } + header { + background-color: #4a90e2; + color: white; + padding: 15px 20px; + text-align: center; + font-size: 24px; + font-weight: 600; + } + main { + max-width: 800px; + margin: 20px auto; + padding: 20px; + background: white; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); + border-radius: 10px; + } + h1 { + font-size: 28px; + margin-bottom: 20px; + color: #4a90e2; + } + .buttons-container { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 15px; + } + .color-button { + display: inline-block; + width: 120px; + height: 120px; + border: none; + border-radius: 10px; + cursor: pointer; + font-size: 18px; + font-weight: 600; + color: white; + text-transform: capitalize; + transition: transform 0.2s, box-shadow 0.2s; + } + .color-button:hover { + transform: translateY(-3px); + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2); + } + #log-container { + margin-top: 30px; + } + #log-container h2 { + font-size: 22px; + margin-bottom: 15px; + } + .log-item { + padding: 10px 15px; + margin-bottom: 10px; + background-color: #f9f9f9; + border-left: 4px solid #4a90e2; + border-radius: 5px; + font-size: 14px; + color: #555; + } + </style> +</head> +<body> + <header>Selector</header> + <main> + <h1>Select a Color</h1> + <div class="buttons-container"> + {% for color in colors %} + <button + class="color-button" + style="background-color: {{ color }};" + onclick="sendColor('{{ color }}')"> + {{ color }} + </button> + {% endfor %} + </div> + <div id="log-container"> + <h2>Logs</h2> + <div id="logs"> + <!-- Logs will be dynamically updated --> + </div> + </div> + </main> + + <script> + // Function to send color to the server + async function sendColor(color) { + try { + const response = await fetch('/publish', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ color: color }), + }); + const result = await response.json(); + if (result.status === "success") { + alert(`Color "${result.color}" sent successfully!`); + } else { + alert("Error sending color."); + } + } catch (error) { + console.error("Error:", error); + } + } + + // Function to fetch logs + async function fetchLogs() { + try { + const response = await fetch('/logs'); + const logs = await response.json(); + const logsContainer = document.getElementById("logs"); + logsContainer.innerHTML = logs.map(log => `<div class="log-item">${log}</div>`).join(""); + } catch (error) { + console.error("Error fetching logs:", error); + } + } + + // Fetch logs every 2 seconds + setInterval(fetchLogs, 2000); + </script> +</body> +</html> +