From 1dc9c36514ea388838d1df6875828d7b9da81256 Mon Sep 17 00:00:00 2001 From: ske087 Date: Wed, 5 Mar 2025 13:18:47 +0200 Subject: [PATCH] updated --- Flask-monitoring/app.py | 91 +++++++++++++++++++ Flask-monitoring/templates/board.html | 93 ++++++++++++++++++++ Flask-monitoring/templates/index.html | 58 ++++++++++++ instance/logs.db | Bin 0 -> 24576 bytes wifi_set_and_server/wifi_set_and_server.ino | 45 +++++++++- 5 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 Flask-monitoring/app.py create mode 100644 Flask-monitoring/templates/board.html create mode 100644 Flask-monitoring/templates/index.html create mode 100644 instance/logs.db diff --git a/Flask-monitoring/app.py b/Flask-monitoring/app.py new file mode 100644 index 0000000..5b55ec5 --- /dev/null +++ b/Flask-monitoring/app.py @@ -0,0 +1,91 @@ +from flask import Flask, request, jsonify, render_template, redirect, url_for +from flask_sqlalchemy import SQLAlchemy +from datetime import datetime, timedelta +import os + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logs.db' +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False +db = SQLAlchemy(app) + +class Log(db.Model): + id = db.Column(db.Integer, primary_key=True) + hostname = db.Column(db.String(100), nullable=False) + message = db.Column(db.String(500), nullable=False) + timestamp = db.Column(db.DateTime, default=datetime.utcnow) + +# Create the database if it does not exist +if not os.path.exists('instance/logs.db'): + with app.app_context(): + db.create_all() + +# Flag to check if tables are created +tables_created = False + +@app.before_request +def create_tables(): + global tables_created + if not tables_created: + db.create_all() + tables_created = True + +@app.route('/log', methods=['POST']) +def log_message(): + data = request.get_json() + hostname = data.get('hostname') + message = data.get('message') + if hostname and message: + new_log = Log(hostname=hostname, message=message) + db.session.add(new_log) + db.session.commit() + return jsonify({'status': 'success', 'message': 'Log saved'}), 201 + return jsonify({'status': 'error', 'message': 'Invalid data'}), 400 + +@app.route('/logs', methods=['GET']) +def get_logs(): + logs = Log.query.all() + return jsonify([{'id': log.id, 'hostname': log.hostname, 'message': log.message, 'timestamp': log.timestamp} for log in logs]) + +@app.route('/cleanup', methods=['DELETE']) +def cleanup_logs(): + cutoff_date = datetime.utcnow() - timedelta(days=10) + Log.query.filter(Log.timestamp < cutoff_date).delete() + db.session.commit() + return jsonify({'status': 'success', 'message': 'Old logs deleted'}) + +@app.route('/') +def index(): + # Get the latest log entry for each board + latest_logs = db.session.query(Log).order_by(Log.timestamp.desc()).all() + boards = {} + for log in latest_logs: + if log.hostname not in boards: + boards[log.hostname] = log + + # Determine the status of each board + board_status = [] + for hostname, log in boards.items(): + time_diff = datetime.utcnow() - log.timestamp + status = 'Online' if time_diff.total_seconds() <= 20 else 'Possible Offline' + board_status.append({'hostname': hostname, 'status': status, 'last_seen': log.timestamp}) + + return render_template('index.html', boards=board_status) + +@app.route('/board/') +def view_board(hostname): + logs = Log.query.filter_by(hostname=hostname).order_by(Log.timestamp.desc()).all() + return render_template('board.html', hostname=hostname, logs=logs) + +@app.route('/delete_board/', methods=['POST']) +def delete_board(hostname): + Log.query.filter_by(hostname=hostname).delete() + db.session.commit() + return redirect(url_for('index')) + +@app.route('/board//logs', methods=['GET']) +def get_board_logs(hostname): + logs = Log.query.filter_by(hostname=hostname).order_by(Log.timestamp.desc()).all() + return jsonify({'logs': [{'timestamp': log.timestamp, 'message': log.message} for log in logs]}) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/Flask-monitoring/templates/board.html b/Flask-monitoring/templates/board.html new file mode 100644 index 0000000..a54fb83 --- /dev/null +++ b/Flask-monitoring/templates/board.html @@ -0,0 +1,93 @@ + + + + + + Board Logs - {{ hostname }} + + + + + +
+
+
+
+ + Back to Home +
+
+
+ Next update in 5 seconds +
+
+
+
+
+
+
Logs for {{ hostname }}
+
    + {% for log in logs %} +
  • + {{ log.timestamp }}: {{ log.message }} +
  • + {% endfor %} +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/Flask-monitoring/templates/index.html b/Flask-monitoring/templates/index.html new file mode 100644 index 0000000..b89571d --- /dev/null +++ b/Flask-monitoring/templates/index.html @@ -0,0 +1,58 @@ + + + + + + ESP Board Status + + + + +
+

ESP Board Status

+
+ {% for board in boards %} +
+
+
+
{{ board.hostname }}
+

Status: + + {{ board.status }} + +

+

Last Seen: {{ board.last_seen }}

+ View Logs +
+
+
+ {% endfor %} +
+
+ + \ No newline at end of file diff --git a/instance/logs.db b/instance/logs.db new file mode 100644 index 0000000000000000000000000000000000000000..1844139f242e7e6e577b478ad5ffccd70f60bc0d GIT binary patch literal 24576 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 literal 0 HcmV?d00001 diff --git a/wifi_set_and_server/wifi_set_and_server.ino b/wifi_set_and_server/wifi_set_and_server.ino index 1afc796..ad923f8 100644 --- a/wifi_set_and_server/wifi_set_and_server.ino +++ b/wifi_set_and_server/wifi_set_and_server.ino @@ -3,9 +3,10 @@ #include // Include the EEPROM library for storing WiFi settings #include // Include the WiFiManager library for managing WiFi connections #include "esp_mac.h" // Include the esp_mac library for MAC address functions +#include // Include the HTTPClient library for sending logs // Version of the code -//ver 0.0.4 +//ver 0.0.11 // Constants for Access Point mode const char* ap_ssid = "ESP32-AP"; // SSID for the Access Point mode @@ -22,10 +23,30 @@ WebServer server(80); // Variables to store WiFi settings String ssid, password, static_ip, netmask, gateway, hostname; +String logServerIP, logServerPort; bool isAPMode = false; // Flag to indicate if the board is in AP mode // Variable to keep track of the last status print time unsigned long lastStatusPrintTime = 0; +unsigned long lastLogTime = 0; // Variable to keep track of the last log time + +// Function to send logs to the log server +void sendLog(String message) { + if (WiFi.status() == WL_CONNECTED && logServerIP.length() > 0 && logServerPort.length() > 0) { + HTTPClient http; + String url = "http://" + logServerIP + ":" + logServerPort + "/log"; + http.begin(url); + http.addHeader("Content-Type", "application/json"); + String payload = "{\"hostname\": \"" + hostname + "\", \"message\": \"" + message + "\"}"; + int httpResponseCode = http.POST(payload); + http.end(); + if (httpResponseCode > 0) { + Serial.println("Log sent successfully: " + message); + } else { + Serial.println("Error sending log: " + message); + } + } +} // Handle the root URL ("/") and serve the configuration page void handleRoot() { @@ -63,6 +84,10 @@ void handleRoot() { html += "
"; html += ""; html += "
"; + html += ""; + html += "
"; + html += ""; + html += "
"; html += ""; html += "
"; html += ""; @@ -119,6 +144,8 @@ void handleSave() { netmask = server.arg("netmask"); gateway = server.arg("gateway"); hostname = server.arg("hostname"); + logServerIP = server.arg("log_server_ip"); + logServerPort = server.arg("log_server_port"); // Save the WiFi settings to EEPROM saveSettings(); @@ -139,8 +166,10 @@ void handleRelay() { if (relay >= 0 && relay < 4) { if (action == "on") { digitalWrite(relayPins[relay], HIGH); + sendLog("Relay " + String(relay + 1) + " turned ON"); } else if (action == "off") { digitalWrite(relayPins[relay], LOW); + sendLog("Relay " + String(relay + 1) + " turned OFF"); } } @@ -157,6 +186,8 @@ void saveSettings() { EEPROM.writeString(96, netmask); EEPROM.writeString(128, gateway); EEPROM.writeString(160, hostname); + EEPROM.writeString(192, logServerIP); + EEPROM.writeString(224, logServerPort); EEPROM.commit(); } @@ -168,12 +199,14 @@ void loadSettings() { netmask = EEPROM.readString(96); gateway = EEPROM.readString(128); hostname = EEPROM.readString(160); + logServerIP = EEPROM.readString(192); + logServerPort = EEPROM.readString(224); } void setup() { Serial.begin(115200); // Start the serial communication Serial.println("Setup started"); - EEPROM.begin(192); // Initialize EEPROM with a size of 192 bytes + EEPROM.begin(256); // Initialize EEPROM with a size of 256 bytes pinMode(userLedPin, OUTPUT); // Set the user LED pin as output digitalWrite(userLedPin, LOW); // Turn off the user LED @@ -248,6 +281,12 @@ void loop() { server.handleClient(); // Handle client requests blinkLed(); // Blink the LED to indicate the mode printStatus(); // Print the status of the board + + // Send a log message every 20 seconds + if (millis() - lastLogTime >= 20000) { + sendLog("Board is functioning"); + lastLogTime = millis(); + } } // Blink the LED to indicate the mode (AP mode or client mode) @@ -344,4 +383,4 @@ String getInterfaceMacAddress(esp_mac_type_t interface) { } return mac; -} +} \ No newline at end of file