diff --git a/app.py b/app.py index c612c21..8879ef5 100644 --- a/app.py +++ b/app.py @@ -1,14 +1,23 @@ from flask import Flask, request, jsonify from datetime import datetime import sqlite3 -from instances.db import init_db +import requests +import os +from instances.db import init_db, DB_PATH +from mission_utils import delayed_post_mission, post_mission, get_robots, get_status app = Flask(__name__) # Variable to store the status of inputs and outputs status = { "input1": "off", - "relay1": "off" + "input2": "off", + "input3": "off", + "input4": "off", + "relay1": "off", + "relay2": "off", + "relay3": "off", + "relay4": "off" } @app.route('/log', methods=['POST']) @@ -26,28 +35,65 @@ def log(): print(f"Board IP address: {ip_address}") print(f"Message: {message}") - # Update the status of inputs and relays based on the message - if 'input1' in message: - status['input1'] = 'on' if 'input1 on' in message else 'off' - print(f"Input 1 is {status['input1']}") - if 'relay1' in message: - status['relay1'] = 'on' if 'relay1 on' in message else 'off' - print(f"Relay 1 status is {status['relay1']}") - # Record the log in the database - conn = sqlite3.connect('logs.db') + conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("INSERT INTO logs (timestamp, hostname, ip_address, message) VALUES (?, ?, ?, ?)", (datetime.now().isoformat(), hostname, ip_address, message)) conn.commit() + print(f"Log entry added: {hostname}, {ip_address}, {message}") + + # Check if the board exists in the database + c.execute("SELECT * FROM boards WHERE ip_address = ?", (ip_address,)) + board = c.fetchone() + + if not board: + # Create a new board entry if it doesn't exist + c.execute('''INSERT INTO boards (hostname, ip_address, input1, input2, input3, input4, relay1, relay2, relay3, relay4) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', + (hostname, ip_address, 'off', 'off', 'off', 'off', 'off', 'off', 'off', 'off')) + conn.commit() + print(f"New board entry created: {hostname}, {ip_address}") + + # Update the status of inputs and relays based on the message + for i in range(1, 5): + if f"Input {i} pressed" in message: + status[f"input{i}"] = 'on' + print(f"Input {i} is {status[f'input{i}']}") + if i == 1: + print("Input 1 is on, triggering delayed_post_mission") + delayed_post_mission({"mission_id": "a1343edc-975c-11ef-87e6-0242ac120002"}) # Example mission ID + c.execute(f'''UPDATE boards SET input{i} = ? WHERE ip_address = ?''', + (status[f"input{i}"], ip_address)) + conn.commit() + print(f"Board status updated: {hostname}, {ip_address}, input{i}={status[f'input{i}']}") + + if f"Input {i} released" in message: + status[f"input{i}"] = 'off' + print(f"Input {i} is {status[f'input{i}']}") + c.execute(f'''UPDATE boards SET input{i} = ? WHERE ip_address = ?''', + (status[f"input{i}"], ip_address)) + conn.commit() + print(f"Board status updated: {hostname}, {ip_address}, input{i}={status[f'input{i}']}") + + for i in range(1, 5): + if f"Relay {i} turned ON" in message: + status[f"relay{i}"] = 'on' + print(f"Relay {i} status is {status[f'relay{i}']}") + c.execute(f'''UPDATE boards SET relay{i} = ? WHERE ip_address = ?''', + (status[f"relay{i}"], ip_address)) + conn.commit() + print(f"Board status updated: {hostname}, {ip_address}, relay{i}={status[f'relay{i}']}") + + if f"Relay {i} turned OFF" in message: + status[f"relay{i}"] = 'off' + print(f"Relay {i} status is {status[f'relay{i}']}") + c.execute(f'''UPDATE boards SET relay{i} = ? WHERE ip_address = ?''', + (status[f"relay{i}"], ip_address)) + conn.commit() + print(f"Board status updated: {hostname}, {ip_address}, relay{i}={status[f'relay{i}']}") - # Update the board status in the database - c.execute('''INSERT OR REPLACE INTO boards (hostname, ip_address, input1, relay1) - VALUES (?, ?, ?, ?)''', - (hostname, ip_address, status['input1'], status['relay1'])) - conn.commit() conn.close() - return jsonify({"message": "Log received"}), 200 @app.route('/control', methods=['POST']) @@ -57,12 +103,14 @@ def control(): return jsonify({"error": "No data provided"}), 400 # Control the relays based on the received data - if 'relay1' in data: - status['relay1'] = data['relay1'] - print(f"Setting Relay 1 to {data['relay1']}") + for i in range(1, 5): + if f'relay{i}' in data: + status[f'relay{i}'] = data[f'relay{i}'] + print(f"Setting Relay {i} to {data[f'relay{i}']}") return jsonify({"message": "Control command received"}), 200 if __name__ == '__main__': init_db() + get_robots() app.run(host='0.0.0.0', port=80) \ No newline at end of file diff --git a/app_schema.txt b/app_schema.txt index 24e4822..040c922 100644 --- a/app_schema.txt +++ b/app_schema.txt @@ -18,13 +18,30 @@ - relay3: TEXT - relay4: TEXT +## Table: mir_server_missions +- ip: TEXT +- authorization: TEXT +- username: TEXT +- password: TEXT +- mission_id: TEXT + +## Table: requested_missions +- state: TEXT +- start_time: TEXT +- mission: TEXT +- mission_name: TEXT +- robot_id: INTEGER +- id: INTEGER PRIMARY KEY + # Explanation of Functions in app.py ## Function: init_db - Initializes the SQLite database. -- Creates two tables: logs and boards. +- Creates four tables: logs, boards, mir_server_missions, and requested_missions. - The logs table stores log entries with timestamp, hostname, IP address, and message. - The boards table stores the status of each board with hostname, IP address, and status of inputs and relays. +- The mir_server_missions table stores the information required to create a JSON post for a mission. +- The requested_missions table stores the response data from the mission post request. ## Function: log - Endpoint: /log @@ -35,6 +52,7 @@ - Updates the status of inputs and relays based on the message. - Records the log in the logs table. - Updates the board status in the boards table. +- Triggers the post_mission function if input1 is turned on. ## Function: control - Endpoint: /control @@ -42,4 +60,11 @@ - Receives control commands to update the status of relays. - Extracts the relay status from the JSON payload. - Prints the new relay status. -- Updates the status of the relays. \ No newline at end of file +- Updates the status of the relays. + +## Function: post_mission +- Sends a mission post request to the MIR server. +- Retrieves the IP, authorization, username, and password from the mir_server_missions table. +- Formats the headers and sends a POST request to the mission scheduler endpoint. +- Prints the result of the mission post request. +- Stores the response data in the requested_missions table. \ No newline at end of file diff --git a/instances/__pycache__/db.cpython-311.pyc b/instances/__pycache__/db.cpython-311.pyc index 932f3dc..0cc4fee 100644 Binary files a/instances/__pycache__/db.cpython-311.pyc and b/instances/__pycache__/db.cpython-311.pyc differ diff --git a/instances/db.py b/instances/db.py index b1b8311..a5505ba 100644 --- a/instances/db.py +++ b/instances/db.py @@ -1,11 +1,26 @@ import sqlite3 +import os + +DB_PATH = os.path.join(os.path.dirname(__file__), 'logs.db') def init_db(): - conn = sqlite3.connect('logs.db') + conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS logs (timestamp TEXT, hostname TEXT, ip_address TEXT, message TEXT)''') c.execute('''CREATE TABLE IF NOT EXISTS boards (hostname TEXT PRIMARY KEY, ip_address TEXT, input1 TEXT, input2 TEXT, input3 TEXT, input4 TEXT, relay1 TEXT, relay2 TEXT, relay3 TEXT, relay4 TEXT)''') + c.execute('''CREATE TABLE IF NOT EXISTS mir_server_missions + (ip TEXT, authorization TEXT, username TEXT, password TEXT, mission_id TEXT PRIMARY KEY)''') + c.execute('''CREATE TABLE IF NOT EXISTS requested_missions + (state TEXT, start_time TEXT, mission TEXT, mission_name TEXT, robot_id INTEGER, id INTEGER PRIMARY KEY)''') + c.execute('''CREATE TABLE IF NOT EXISTS robots + (ip TEXT PRIMARY KEY, url TEXT)''') + conn.commit() + + # Insert a first row into the mir_server_missions table + c.execute('''INSERT OR IGNORE INTO mir_server_missions (ip, authorization, username, password, mission_id) + VALUES (?, ?, ?, ?, ?)''', + ("10.76.153.4", "Basic ZGlzdHJpYnV0b3I6Y2RjYjhiNjAzYzFhZDNjNjVkZTM4ZGY2OWU5YjFkM2ZhMDA2OWEwMDcyMzZkMDNkOGVhNjMyNDVhMDg3YjJkZA==", "distributor", "cdc8b603c1ad3c65de38df69e9b1d3fa0069a007236d03d8ea63245a087b2dd", "a1343edc-975c-11ef-87e6-0242ac120002")) conn.commit() conn.close() \ No newline at end of file diff --git a/instances/logs.db b/instances/logs.db new file mode 100644 index 0000000..5ab4637 Binary files /dev/null and b/instances/logs.db differ diff --git a/logs.db b/logs.db deleted file mode 100644 index 2c6aec5..0000000 Binary files a/logs.db and /dev/null differ diff --git a/mission_utils.py b/mission_utils.py new file mode 100644 index 0000000..c560dac --- /dev/null +++ b/mission_utils.py @@ -0,0 +1,106 @@ +import time +import sqlite3 +import requests +from instances.db import DB_PATH + +def delayed_post_mission(mission_id): + print("Starting delayed_post_mission function") + time.sleep(5) # Delay for 5 seconds + post_mission(mission_id) + +def post_mission(mission_id): + print("Starting post_mission function") + conn = sqlite3.connect(DB_PATH) + c = conn.cursor() + c.execute("SELECT ip, authorization, username, password FROM mir_server_missions LIMIT 1") + row = c.fetchone() + conn.close() + + if row: + ip, authorization, username, password = row + print(f"Retrieved MIR server details: IP={ip}, Authorization={authorization}") + f_host = f"http://{ip}/api/v2.0.0/" + headers = { + "accept": "application/json", + "Authorization": authorization, + "Accept-Language": "en_US", + "Content-Type": "application/json" + } + print(f"Sending POST request to {f_host}mission_scheduler with mission_id={mission_id}") + response = requests.post(f"{f_host}mission_scheduler", headers=headers, json=mission_id) + print(f"Received response with status code {response.status_code}") + if response.status_code in {200, 201}: + print("Mission sent successfully") + response_data = response.json() + conn = sqlite3.connect(DB_PATH) + c = conn.cursor() + c.execute("INSERT INTO requested_missions (state, start_time, mission, mission_name, robot_id, id) VALUES (?, ?, ?, ?, ?, ?)", + (response_data['state'], response_data['start_time'], response_data['mission'], response_data['mission_name'], response_data['robot_id'], response_data['id'])) + conn.commit() + conn.close() + else: + print(f"Failed to send mission, status code: {response.status_code}, response: {response.text}") + else: + print("No MIR server details found in the database") + +def get_robots(): + fleetip = "10.76.153.4" + f_host = f"http://{fleetip}/api/v2.0.0/" + headers = { + "accept": "application/json", + "Authorization": "Basic ZGlzdHJpYnV0b3I6Y2RjYjhiNjAzYzFhZDNjNjVkZTM4ZGY2OWU5YjFkM2ZhMDA2OWEwMDcyMzZkMDNkOGVhNjMyNDVhMDg3YjJkZA==", + "Accept-Language": "en_US", + "Content-Type": "application/json" + } + + # Get robots URL for next posts + response = requests.get(f_host + "robots", headers=headers) + print(f"Response status code: {response.status_code}") + print(f"Response content: {response.text}") + + if response.status_code == 200: + try: + robots = response.json() + print(robots) + except requests.exceptions.JSONDecodeError as e: + print(f"Error decoding JSON: {e}") + return + except ValueError as e: + print(f"Error decoding JSON: {e}") + return + + conn = sqlite3.connect(DB_PATH) + c = conn.cursor() + for robot in robots: + ip = robot['ip'] + url = robot['url'] + c.execute('''INSERT OR REPLACE INTO robots (ip, url) VALUES (?, ?)''', (ip, url)) + conn.commit() + conn.close() + else: + print(f"Failed to get robots. Status code: {response.status_code}, Response: {response.text}") + +def get_status(robotid): + conn = sqlite3.connect(DB_PATH) + c = conn.cursor() + c.execute("SELECT ip, url FROM robots WHERE ip = ?", (robotid,)) + row = c.fetchone() + conn.close() + + if row: + ip, url = row + host = f"http://{ip}/api" + headers = { + "accept": "application/json", + "Authorization": "Basic ZGlzdHJpYnV0b3I6Y2RjYjhiNjAzYzFhZDNjNjVkZTM4ZGY2OWU5YjFkM2ZhMDA2OWEwMDcyMzZkMDNkOGVhNjMyNDVhMDg3YjJkZA==", + "Accept-Language": "en_US", + "Content-Type": "application/json" + } + + get_robot_id = requests.get(host + url, headers=headers) + status = get_robot_id.json() + mission_text = status['status']['mission_text'] + return mission_text + else: + print("No robot details found in the database") + return None \ No newline at end of file diff --git a/query_db.py b/query_db.py new file mode 100644 index 0000000..91012a6 --- /dev/null +++ b/query_db.py @@ -0,0 +1,24 @@ +import sqlite3 +import os +from instances.db import DB_PATH + +def query_last_20_entries(table_name): + conn = sqlite3.connect(DB_PATH) + c = conn.cursor() + query = f"SELECT * FROM {table_name} ORDER BY ROWID DESC LIMIT 20" + c.execute(query) + rows = c.fetchall() + conn.close() + return rows + +def print_entries(table_name, entries): + print(f"Last 20 entries from {table_name}:") + for entry in entries: + print(entry) + print("\n") + +if __name__ == '__main__': + tables = ['logs', 'boards', 'mir_server_missions', 'requested_missions'] + for table in tables: + entries = query_last_20_entries(table) + print_entries(table, entries) \ No newline at end of file