from flask import Flask, request, jsonify, render_template, redirect, url_for, flash from flask_sqlalchemy import SQLAlchemy from datetime import datetime, timedelta import os import threading import requests app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///logs.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.secret_key = 'supersecretkey' db = SQLAlchemy(app) class Log(db.Model): id = db.Column(db.Integer, primary_key=True) hostname = db.Column(db.String(100), nullable=False) ip_address = db.Column(db.String(100), nullable=False) message = db.Column(db.String(500), nullable=False) timestamp = db.Column(db.DateTime, default=datetime.utcnow) relay_status = db.Column(db.String(4), default='off,off,off,off') # Status of 4 relays input_status = db.Column(db.String(4), default='off,off,off,off') # Status of 4 inputs # 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') ip_address = data.get('ip_address') message = data.get('message') relay_status = data.get('relay_status', 'off,off,off,off') input_status = data.get('input_status', 'off,off,off,off') if hostname and ip_address and message: # Parse the message to update relay status if "Relay" in message and "turned" in message: parts = message.split() relay_index = int(parts[1]) - 1 action = parts[3].lower() relay_status_list = relay_status.split(',') relay_status_list[relay_index] = action relay_status = ','.join(relay_status_list) new_log = Log(hostname=hostname, ip_address=ip_address, message=message, relay_status=relay_status, input_status=input_status) 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(hours=app.config.get('CLEANUP_TIME', 24)) 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()).limit(50).all() relay_status = ['off', 'off', 'off', 'off'] input_status = ['off', 'off', 'off', 'off'] if logs: latest_log = logs[0] relay_status = latest_log.relay_status.split(',') input_status = latest_log.input_status.split(',') ip_address = logs[0].ip_address if logs else '' # Get the IP address from the logs last_update = logs[0].timestamp if logs else None # Get the last update time return render_template('board.html', hostname=hostname, ip_address=ip_address, logs=logs, relay_status=relay_status, input_status=input_status, last_update=last_update) @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]}) @app.route('/board//relay//', methods=['POST']) def control_relay(hostname, relay, action): log = Log.query.filter_by(hostname=hostname).order_by(Log.timestamp.desc()).first() if log: ip_address = log.ip_address url = f"http://{ip_address}/relay" payload = { "relay": relay, "action": action } try: response = requests.post(url, data=payload) if response.status_code == 200: return redirect(url_for('view_board', hostname=hostname)) else: return f"Failed to control relay: {response.text}", 500 except Exception as e: return f"Error controlling relay: {e}", 500 else: return f"No logs found for hostname: {hostname}", 404 @app.route('/settings', methods=['GET']) def settings(): cleanup_time = app.config.get('CLEANUP_TIME', 24) return render_template('settings.html', cleanup_time=cleanup_time) @app.route('/set_cleanup_time', methods=['POST']) def set_cleanup_time(): cleanup_time = request.form.get('cleanup_time') if cleanup_time: app.config['CLEANUP_TIME'] = int(cleanup_time) flash('Cleanup time set successfully!', 'success') else: flash('Invalid cleanup time!', 'danger') return redirect(url_for('settings')) @app.route('/run_cleanup_now', methods=['POST']) def run_cleanup_now(): with app.app_context(): cutoff_date = datetime.utcnow() - timedelta(hours=app.config.get('CLEANUP_TIME', 24)) Log.query.filter(Log.timestamp < cutoff_date).delete() db.session.commit() flash('Cleanup executed successfully!', 'success') return redirect(url_for('settings')) def post_action_to_server(hostname, action): url = "http://your-server-url.com/action" payload = { "hostname": hostname, "action": action } try: response = requests.post(url, json=payload) if response.status_code == 200: print(f"Action posted successfully: {action}") else: print(f"Failed to post action: {action}") except Exception as e: print(f"Error posting action: {e}") def schedule_cleanup(): with app.app_context(): cutoff_date = datetime.utcnow() - timedelta(hours=app.config.get('CLEANUP_TIME', 24)) Log.query.filter(Log.timestamp < cutoff_date).delete() db.session.commit() threading.Timer(3600, schedule_cleanup).start() if __name__ == '__main__': schedule_cleanup() # Start the cleanup scheduler app.run(host='0.0.0.0', port=5000)