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 0000000..1844139 Binary files /dev/null and b/instance/logs.db differ 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