From 4e60cd9ad054374c9f3e96883dcdf6a894446e65 Mon Sep 17 00:00:00 2001 From: caliskanbi Date: Mon, 15 May 2023 10:50:19 +0200 Subject: [PATCH] Error Handling BackEnd added, logging included, order list and robot class added --- .idea/deployment.xml | 14 +++ .idea/sshConfigs.xml | 8 ++ .idea/webServers.xml | 14 +++ requirements.txt | 2 +- software/backend/backend_database.db | Bin 16384 -> 16384 bytes software/backend/data_functions.py | 105 +++++++++++++----- .../dev_test_examples/mqtt_publisher.py | 19 ++-- software/backend/main.py | 59 ++++++---- software/backend/plantdatabase.py | 74 +++++++----- software/backend/robot.py | 47 ++++++++ software/backend/tests/test_database.db | Bin 16384 -> 16384 bytes software/defines.py | 5 +- 12 files changed, 256 insertions(+), 91 deletions(-) create mode 100644 .idea/deployment.xml create mode 100644 .idea/sshConfigs.xml create mode 100644 .idea/webServers.xml create mode 100644 software/backend/robot.py diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..efacd62 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/sshConfigs.xml b/.idea/sshConfigs.xml new file mode 100644 index 0000000..4a6426e --- /dev/null +++ b/.idea/sshConfigs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/webServers.xml b/.idea/webServers.xml new file mode 100644 index 0000000..51d8c58 --- /dev/null +++ b/.idea/webServers.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c983847..04e64e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,4 +29,4 @@ urllib3==1.26.14 Werkzeug==2.2.3 zipp==3.15.0 python-ev3dev2==2.1.0.post1 -pytest \ No newline at end of file +pytest==7.3.1 \ No newline at end of file diff --git a/software/backend/backend_database.db b/software/backend/backend_database.db index f8ce5be04e4d95d1b32a1877de2bd4b37081e8e3..ac54c93e1f8feebf7ec7f1d659a885325bb77435 100644 GIT binary patch delta 779 zcmZ{iJ4*vW6oq%QN+!AwpNXP@G%6OOGdnxG<~A9y5G27y5K*uZYr#&zjc9411dC`P z{sAHCAFx*uEW}D|1Z%;@#@Sgg#w54dVm{72=iDuq^>SH18qp_?M`t@Hw5g@}+WOga zkg+sP%b1&*^Xl9>=gzLP>VPw3f7?&?jeTNo*ny3#59`X>w-&82^UHiN&&|!+9+)A{ zAdRJxNtAGj%P`@X@*J4~5&)yZAFj$d6{ThMH5PEX4ekT?>iC8lV|jcq!u4i#7d)00 zrLB-fW31tUHo6q3FZjFClf1$cpSZsj9sth+Wp(`UPR@Pe8TYlp{SaJU=cAC-Q_1(X z;XQC&!Q*tI^b+HbyeGz!4IKvH$_}Oau);(s4pBJRew(`-*wH7m4$?xFLg-KTZjQ~0=8P?RCeMw;cM88@UY?XN}dMb&HSFSc&#co4zt}6 z|KBW=X9vO)E7`8r&t6_O+`-3F%ADR9mBF;k8o7%*%4@X|Btf|aq2K>ex?(`&8kS2| LE(+-iDLnoFdceDe delta 63 zcmZo@U~Fh$oFL68K2gS*Rh&UDnQ>#vY<+QdUIqpRc76#4{`>p~`RDW3@yGC6@k?wL T6ky_KQedCF&|Yk^f&B#l(Tfh* diff --git a/software/backend/data_functions.py b/software/backend/data_functions.py index d7d28f1..69bc018 100644 --- a/software/backend/data_functions.py +++ b/software/backend/data_functions.py @@ -10,73 +10,103 @@ from software.defines import Topics, MAX_PLANT_COUNT import json import uuid from typing import Union +from datetime import datetime +import logging +from robot import Robot # Robot Channel Reactions def data_sensordata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase, - order_handler: list): - print("message received") - # TODO: Store data in database + robot: Robot): str_in = str(message.payload.decode("UTF-8")) payload = json.loads(str_in) - print("Received data: ", json.dumps(payload)) + logging.info("ROBOT_DATA_SENSORDATA Received data: " + json.dumps(payload)) + drive_data = { + "PlantID": payload['PlantID'], + "ActionID": payload['ActionID'] + } - order_handler.remove(payload['ActionID']) + try: + robot.delete_order(drive_data) + except Exception as e: + logging.error("Could not delete order: " + str(e)) mydatabase.insert_measurement_data(plant_id=payload['PlantID'], sensordata_temp=payload['AirTemperature'], sensordata_humidity=payload['AirHumidity'], sensordata_soil_moisture=payload['SoilMoisture'], sensordata_brightness=payload['Brightness']) + logging.debug("Inserted to data base: " + json.dumps(payload)) -def data_position(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): - # TODO: Forward to frontend in json format - client.publish(Topics['BACKEND_DATA_POSITION'], message.payload.decode("utf-8")) +def data_position(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot): + logging.info("ROBOT_DATA_POSITION Received data: " + json.dumps(message.payload.decode("UTF-8"))) + robot.store_position(json.loads(message.payload.decode("UTF-8"))["Position"]) + position_data = { + "Position": robot.get_position(), + "Timestamp": str(datetime.now()) + } + client.publish(Topics['BACKEND_DATA_POSITION'], json.dumps(position_data)) -def data_battery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): - # TODO: Forward to frontend in json format - client.publish(Topics['BACKEND_DATA_BATTERY'], message.payload.decode("utf-8")) +def data_battery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot): + logging.info("ROBOT_DATA_BATTERY Received data: " + json.dumps(message.payload.decode("UTF-8"))) + robot.store_battery(json.loads(message.payload.decode("UTF-8"))["Battery"]) + battery_data = { + "Battery": robot.get_battery(), + "Timestamp": str(datetime.now()) + } + client.publish(Topics['BACKEND_DATA_BATTERY'], json.dumps(battery_data)) # FrontEnd Channel Reactions def action_drive(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase, - order_handler: list): - # TODO: ROBOT READY CHECK - if len(order_handler) < 5: - order_handler.append(uuid.uuid4()) + robot: Robot): + plant_id = mydatabase.get_plant_id(plant_name=json.loads(message.payload.decode("UTF-8"))["PlantName"]) + action_id = str(uuid.uuid4()) + drive_data = { + "PlantID": plant_id, + "ActionID": action_id + } + + if robot.get_order_number() < 5 and robot.get_robot_status() is True: + robot.add_order(drive_data) + client.publish(Topics['ROBOT_ACTION_DRIVE'], json.dumps(drive_data)) + logging.info("BACKEND_ACTION_DRIVE Drive Command published: " + json.dumps(drive_data)) else: - # TODO: What to do when no place in order_list left - pass - client.publish(Topics['ROBOT_ACTION_DRIVE'], message.payload.decode("utf-8")) + if robot.get_order_number() < 5: + robot.add_order(drive_data) + logging.info("BACKEND_ACTION_DRIVE New data added to order list: " + str(drive_data)) + elif robot.get_order_number() >= 5: + logging.error("Could not add Order to list. Order discarded") + client.publish(Topics['BACKEND_DATA_ERROR'], "Could not add Order to list. Order discarded") -def action_driveall(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): +def action_driveall(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase, + robot: Robot): # TODO: Implement here - pass + print("HELLO") def action_getposition(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): client.publish(Topics['ROBOT_ACTION_GETPOSITION']) + logging.info("BACKEND_ACTION_GETPOSITION message forwarded to Robot") -def action_getbattery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): +def action_getbattery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage): client.publish(Topics['ROBOT_ACTION_GETBATTERY']) + logging.info("BACKEND_ACTION_GETBATTERY message forwarded to Robot") def action_getalldata(client: mqtt.Client, userdata, message: Union[mqtt.MQTTMessage, list], mydatabase: PlantDataBase): plant_names = mydatabase.get_plant_names() - print(type(plant_names)) alldata = [] for i in plant_names: - print("I Type: " + str(type(i))) - print("I: " + i[0]) alldata.append(mydatabase.get_latest_data(plant_name=i[0])) client.publish(Topics['BACKEND_DATA_SENSORDATAALL'], json.dumps(alldata)) - print("BACKEND_DATA_SENSORDATAALL SEND DATA:" + str(alldata)) + logging.info("BACKEND_DATA_SENSORDATAALL got data from database:" + str(alldata)) def action_newplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): @@ -87,8 +117,7 @@ def action_newplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, my sensordata_humidity=plant_data["AirHumidity"], sensordata_soil_moisture=plant_data["SoilMoisture"], sensordata_brightness=plant_data["Brightness"]) - print("BACKEND_ACTION_NEWPLANT RECEIVED DATA: " + str(plant_data)) - print(mydatabase.get_plant_names()) + logging.info("BACKEND_ACTION_NEWPLANT new plant data received and inserted: " + str(plant_data)) action_getalldata(client, userdata, message, mydatabase) @@ -100,14 +129,14 @@ def action_configureplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessa sensordata_humidity=plant_data["AirHumidity"], sensordata_soil_moisture=plant_data["SoilMoisture"], sensordata_brightness=plant_data["Brightness"]) - print("BACKEND_ACTION_CONFIGUREPLANT RECEIVED DATA: " + str(plant_data)) + logging.info("BACKEND_ACTION_CONFIGUREPLANT configure plant data received and inserted: " + str(plant_data)) action_getalldata(client, userdata, message, mydatabase) def action_deleteplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): delete_plant = json.loads(message.payload.decode("UTF-8")) mydatabase.delete_plant(plant_id=delete_plant) - print("BACKEND_ACTION_DELETEPLANT RECEIVED DATA: " + str(delete_plant)) + logging.info("BACKEND_ACTION_DELETEPLANT delete plant data received and deleted: " + str(delete_plant)) action_getalldata(client, userdata, message, mydatabase) @@ -118,4 +147,20 @@ def action_countplants(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, "MaxCount": MAX_PLANT_COUNT } client.publish(Topics["BACKEND_DATA_PLANTCOUNT"], json.dumps(count_payload)) - print("BACKEND_DATA_PLANTCOUNT SEND DATA: " + str(count_payload)) + logging.info("BACKEND_DATA_PLANTCOUNT forwarded plant count to FrontEnd: " + str(count_payload)) + + +def data_error(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot): + robot.store_last_error(message.payload.decode("UTF-8")) + logging.error("ROBOT_DATA_ERROR new error received from Robot: " + robot.get_last_error()) + client.publish(Topics['BACKEND_DATA_ERROR'], message.payload.decode("UTF-8")) + + +def data_robotready(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot): + robot.change_robot_status(message.payload.decode("UTF-8") == 'True') + if robot.get_robot_status() is True and robot.get_order_number() >= 1: + client.publish(Topics['ROBOT_ACTION_DRIVE'], json.dumps(robot.get_next_order())) + logging.info("Waiting Order send to Robot") + + logging.info("ROBOT_DATA_ROBOTREADY status updated: " + str(robot.get_robot_status())) + client.publish(Topics['BACKEND_DATA_ROBOTREADY'], message.payload.decode("UTF-8")) diff --git a/software/backend/dev_test_examples/mqtt_publisher.py b/software/backend/dev_test_examples/mqtt_publisher.py index 2e3d51c..c2d1091 100644 --- a/software/backend/dev_test_examples/mqtt_publisher.py +++ b/software/backend/dev_test_examples/mqtt_publisher.py @@ -1,10 +1,12 @@ import paho.mqtt.client as mqtt + +import software.defines from software.defines import MQTT_BROKER_LOCAL from random import randrange, uniform import time import json from software.defines import Topics, PLANTDATA -mqttBroker = "192.168.178.182" +mqttBroker = software.defines.MQTT_BROKER_GLOBAL def on_connect(client, userdata, flags, rc): @@ -20,17 +22,10 @@ client.on_connect = on_connect client.connect(mqttBroker) plantdata = { - "AirTemperature": 20.4, - "AirHumidity": 7.0, - "SoilMoisture": 5.0, - "Brightness": 39, - "PlantID": 2, - "Timestamp": "hallo", - "MeasurementID": 187 + "PlantName": "Kemal" } print(type(PLANTDATA)) -while True: - client.publish("TEST", json.dumps(plantdata)) - print(json.dumps(plantdata)) - time.sleep(2) +client.publish("BACKEND/ACTION/GETBATTERY", json.dumps(plantdata)) +print(json.dumps(plantdata)) +time.sleep(2) diff --git a/software/backend/main.py b/software/backend/main.py index 8aae264..6a89c44 100644 --- a/software/backend/main.py +++ b/software/backend/main.py @@ -12,17 +12,17 @@ import paho.mqtt.client as mqtt from software.defines import MQTT_BROKER_LOCAL, MQTT_BROKER_GLOBAL, Topics, BACKEND_CLIENT_ID, DATABASE_NAME from plantdatabase import PlantDataBase import data_functions - -# inits -mydatabase = PlantDataBase(database_name=DATABASE_NAME) -mydatabase.create_tables() -order_handler = [] # will contain UUIDS with Order IDs +import logging +import sys +from robot import Robot -def on_connect(_client: mqtt.Client, _userdata, _flags, _rc): +def on_connect(_client: mqtt.Client, _userdata, _flags, _rc, _mydatabase, _robot): """ This method gets called, when it connects to a mqtt broker. It is used to subscribe to the specific topics + :param _robot: + :param _mydatabase: :param _client: mqtt client object :param _userdata: :param _flags: @@ -37,25 +37,25 @@ def on_connect(_client: mqtt.Client, _userdata, _flags, _rc): # From Robot: _client.subscribe(Topics['ROBOT_DATA_SENSORDATA']) _client.message_callback_add(Topics['ROBOT_DATA_SENSORDATA'], lambda client, userdata, message: data_functions. - data_sensordata(client, userdata, message, mydatabase, order_handler)) + data_sensordata(client, userdata, message, _mydatabase, _robot)) _client.subscribe(Topics['ROBOT_DATA_POSITION']) _client.message_callback_add(Topics['ROBOT_DATA_POSITION'], data_functions.data_position) _client.subscribe(Topics['ROBOT_DATA_BATTERY']) _client.message_callback_add(Topics['ROBOT_DATA_BATTERY'], lambda client, userdata, message: data_functions. - data_battery(client, userdata, message, mydatabase)) + data_battery(client, userdata, message)) # client.subscribe('Robot/Data/Picture') # From FrontEnd: _client.subscribe(Topics['BACKEND_ACTION_DRIVE']) _client.message_callback_add(Topics['BACKEND_ACTION_DRIVE'], lambda client, userdata, message: data_functions. - action_drive(client, userdata, message, mydatabase, order_handler)) + action_drive(client, userdata, message, _mydatabase, _robot)) _client.subscribe(Topics['BACKEND_ACTION_DRIVEALL']) - _client.message_callback_add(Topics['BACKEND_ACTION_DRIVE'], lambda client, userdata, message: data_functions. - action_driveall(client, userdata, message, mydatabase)) + _client.message_callback_add(Topics['BACKEND_ACTION_DRIVEALL'], lambda client, userdata, message: data_functions. + action_driveall(client, userdata, message, _mydatabase, _robot)) _client.subscribe(Topics['BACKEND_ACTION_GETPOSITION']) _client.message_callback_add(Topics['BACKEND_ACTION_GETPOSITION'], data_functions.action_getposition) @@ -66,35 +66,54 @@ def on_connect(_client: mqtt.Client, _userdata, _flags, _rc): _client.subscribe(Topics['BACKEND_ACTION_GETALLDATA']) _client.message_callback_add(Topics['BACKEND_ACTION_GETALLDATA'], lambda client, userdata, message: data_functions. - action_getalldata(client, userdata, message, mydatabase)) + action_getalldata(client, userdata, message, _mydatabase)) _client.subscribe(Topics['BACKEND_ACTION_NEWPLANT']) _client.message_callback_add(Topics['BACKEND_ACTION_NEWPLANT'], lambda client, userdata, message: data_functions. - action_newplant(client, userdata, message, mydatabase)) + action_newplant(client, userdata, message, _mydatabase)) _client.subscribe(Topics['BACKEND_ACTION_CONFIGUREPLANT']) _client.message_callback_add(Topics['BACKEND_ACTION_CONFIGUREPLANT'], lambda client, userdata, message: data_functions. - action_configureplant(client, userdata, message, mydatabase)) + action_configureplant(client, userdata, message, _mydatabase)) _client.subscribe(Topics['BACKEND_ACTION_DELETEPLANT']) _client.message_callback_add(Topics['BACKEND_ACTION_DELETEPLANT'], lambda client, userdata, message: data_functions. - action_deleteplant(client, userdata, message, mydatabase)) + action_deleteplant(client, userdata, message, _mydatabase)) _client.subscribe(Topics['BACKEND_ACTION_PLANTCOUNT']) _client.message_callback_add(Topics['BACKEND_ACTION_PLANTCOUNT'], lambda client, userdata, message: data_functions. - action_countplants(client, userdata, message, mydatabase)) + action_countplants(client, userdata, message, _mydatabase)) + _client.subscribe(Topics['ROBOT_DATA_ERROR']) + _client.message_callback_add(Topics['ROBOT_DATA_ERROR'], lambda client, userdata, message: data_functions. + data_error(client, userdata, message, _robot)) + + _client.subscribe(Topics['ROBOT_DATA_ROBOTREADY']) + _client.message_callback_add(Topics['ROBOT_DATA_ROBOTREADY'], lambda client, userdata, message: data_functions. + data_robotready(client, userdata, message, _robot)) # END TOPIC SUBSCRIPTIONS else: print("connection failed") def main(): - client = mqtt.Client(BACKEND_CLIENT_ID) - client.on_connect = on_connect - client.connect(MQTT_BROKER_GLOBAL) - client.loop_forever() + robot = Robot() + my_database = PlantDataBase(database_name=DATABASE_NAME) + my_database.create_tables() + mqttclient = mqtt.Client(BACKEND_CLIENT_ID) + mqttclient.on_connect = lambda client, userdata, flags, rc: on_connect(_client=client, + _userdata=userdata, + _flags=flags, + _rc=rc, + _mydatabase=my_database, + _robot=robot) + mqttclient.connect(MQTT_BROKER_GLOBAL) + logging.basicConfig(filename="server.log", filemode="a", encoding="utf-8", level=logging.DEBUG, + format='%(asctime)s %(name)s %(levelname)s %(message)s', + datefmt="%d-%m-%Y %H:%M:%S") + logging.getLogger().addHandler(logging.StreamHandler(sys.stdout)) + mqttclient.loop_forever() if __name__ == "__main__": diff --git a/software/backend/plantdatabase.py b/software/backend/plantdatabase.py index a2de15d..fb89f77 100644 --- a/software/backend/plantdatabase.py +++ b/software/backend/plantdatabase.py @@ -1,6 +1,7 @@ # file to create a database via python script import sqlite3 from typing import Optional +import logging class PlantDataBase: @@ -13,9 +14,8 @@ class PlantDataBase: self.conn = None try: self.conn = sqlite3.connect(self.db_file, check_same_thread=False) - print(sqlite3.version) except sqlite3.Error as e: - print(e) + logging.error("Database init error: " + str(e)) self.cur = self.conn.cursor() def create_tables(self): @@ -38,32 +38,36 @@ class PlantDataBase: self.cur.execute(table_config) return True except sqlite3.Warning as e: - return e + logging.error("Could not create tables: " + str(e)) + return False - def insert_plant(self, plantname: str, plant_id: int): + def insert_plant(self, plantname: str, plant_id: int) -> bool: try: self.cur.execute("INSERT INTO plants (PlantName, PlantID) VALUES (?,?)", (plantname, plant_id)) self.conn.commit() return True - except (sqlite3.NotSupportedError, sqlite3.Warning) as e: - return e + except Exception as e: + logging.error("Could not insert plant: " + str(e)) + return False - def configure_plant(self, plant_id: int, plantname: str): + def configure_plant(self, plant_id: int, plantname: str) -> bool: try: self.cur.execute("UPDATE plants SET PlantID = ?, PlantName = ? WHERE PlantID= ?", (plant_id, plantname, plant_id)) self.conn.commit() return True - except (sqlite3.NotSupportedError, sqlite3.Warning) as e: - return e + except Exception as e: + logging.error("Could not configure plant: " + str(e)) + return False def delete_plant(self, plant_id): try: self.cur.execute('DELETE FROM plants WHERE PlantID = ?', (plant_id,)) self.conn.commit() return True - except (sqlite3.NotSupportedError, sqlite3.Warning) as e: - return e + except Exception as e: + logging.error("Could not delete plant: " + str(e)) + return False def insert_measurement_data(self, plant_id, sensordata_temp, @@ -72,13 +76,14 @@ class PlantDataBase: sensordata_brightness) -> bool: try: self.cur.execute(f"INSERT INTO measurement_values (PlantID, AirTemperature, AirHumidity," - f"SoilMoisture, Brightness) VALUES " - f"({plant_id}, {sensordata_temp}, {sensordata_humidity}, {sensordata_soil_moisture}" - f", {sensordata_brightness})") + f"SoilMoisture, Brightness) VALUES " + f"({plant_id}, {sensordata_temp}, {sensordata_humidity}, {sensordata_soil_moisture}" + f", {sensordata_brightness})") self.conn.commit() return True - except (sqlite3.NotSupportedError, sqlite3.Warning) as e: - return e + except Exception as e: + logging.error("Could not insert measurement data: " + str(e)) + return False def get_latest_data(self, plant_name: Optional[str] = None, plant_id: Optional[int] = None): """ @@ -108,27 +113,42 @@ class PlantDataBase: "PlantName": plant_name } return json_file - except (sqlite3.Warning, TypeError) as e: - return e + + except Exception as e: + logging.error("Could not get measurement values: " + str(e)) def delete_data(self, table_name): - self.cur.execute(f'DELETE FROM {table_name}') - self.conn.commit() - return True - - # TODO: Kemals Scheiß implementieren + try: + self.cur.execute(f'DELETE FROM {table_name}') + self.conn.commit() + return True + except Exception as e: + logging.error("Could not delete data: " + str(e)) def plant_count(self) -> int: """ returns the number of plants registered in the database :return: """ - self.cur.execute("SELECT COUNT(*) FROM plants") - return self.cur.fetchone()[0] + try: + self.cur.execute("SELECT COUNT(*) FROM plants") + return self.cur.fetchone()[0] + except Exception as e: + logging.error("Could not count plants: " + str(e)) def get_plant_names(self) -> list: - self.cur.execute("SELECT PlantName FROM plants") - return self.cur.fetchall() + try: + self.cur.execute("SELECT PlantName FROM plants") + return self.cur.fetchall() + except Exception as e: + logging.error("Could not get plant names: " + str(e)) + + def get_plant_id(self, plant_name: str) -> int: + try: + self.cur.execute("SELECT PlantID FROM plants WHERE PlantName=?", (plant_name,)) + return self.cur.fetchone()[0] + except Exception as e: + logging.error("Could not get plant id: " + str(e)) def __del__(self): self.conn.close() diff --git a/software/backend/robot.py b/software/backend/robot.py new file mode 100644 index 0000000..96cb5e1 --- /dev/null +++ b/software/backend/robot.py @@ -0,0 +1,47 @@ +class Robot: + """ + This class contains the features of the robot. It is used as an interface for the main to avoid global variables and + store them instead in an instance of this robot object + """ + def __init__(self): + self.robot_ready = True + self.order_handler = [] + self.battery = 0 + self.position = "" + self.last_error = "" + + def change_robot_status(self, status: bool): + self.robot_ready = status + + def add_order(self, drivedata): + self.order_handler.append(drivedata) + + def delete_order(self, drivedata): + self.order_handler.remove(drivedata) + + def get_next_order(self): + return self.order_handler[0] + + def get_order_number(self): + return len(self.order_handler) + + def store_battery(self, battery): + self.battery = battery + + def store_position(self, position): + self.position = position + + def store_last_error(self, error): + self.last_error = error + + def get_battery(self): + return self.battery + + def get_position(self): + return self.position + + def get_last_error(self): + return self.last_error + + def get_robot_status(self): + return self.robot_ready diff --git a/software/backend/tests/test_database.db b/software/backend/tests/test_database.db index d38a441576b6de3bf15f72fc692859383da61c95..a6d863c40428284491104fc2ce73ad8f350b6334 100644 GIT binary patch delta 116 zcmZo@U~Fh$oFL6;Hc`fz(QISFWPN>JE=Fca#)6#0ypm!zUIqpRUS3lM{*(NZ_@nt% z_}=nuR_j diff --git a/software/defines.py b/software/defines.py index 9bc3e77..2f3786c 100644 --- a/software/defines.py +++ b/software/defines.py @@ -21,6 +21,8 @@ Topics = { "ROBOT_DATA_BATTERY": "ROBOT/DATA/BATTERY", "ROBOT_DATA_POSITION": "ROBOT/DATA/POSITION", "ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", + "ROBOT_DATA_ERROR": "ROBOT/DATA/ERROR", + "ROBOT_DATA_ROBOTREADY": "ROBOT/DATA/ROBOTREADY", "BACKEND_ACTION_DRIVE": "BACKEND/ACTION/DRIVE", "BACKEND_ACTION_DRIVEALL": "BACKEND/ACTION/DRIVEALL", @@ -38,7 +40,8 @@ Topics = { "BACKEND_DATA_BATTERY": "BACKEND/DATA/BATTERY", "BACKEND_DATA_PICTURE": "BACKEND/DATA/PICTURE", "BACKEND_DATA_PLANTCOUNT": "BACKEND/DATA/PLANTCOUNT", - + "BACKEND_DATA_ERROR": "BACKEND/DATA/ERROR", + "BACKEND_DATA_ROBOTREADY": "BACKEND/DATA/ROBOTREADY" }