@@ -0,0 +1,14 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="PublishConfigData" serverName="backend" remoteFilesAllowedToDisappearOnAutoupload="false"> | |||
<serverData> | |||
<paths name="backend"> | |||
<serverdata> | |||
<mappings> | |||
<mapping deploy="/home/lego/SMARTGARDENING" local="$PROJECT_DIR$/software" web="/" /> | |||
</mappings> | |||
</serverdata> | |||
</paths> | |||
</serverData> | |||
</component> | |||
</project> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="SshConfigs"> | |||
<configs> | |||
<sshConfig authType="PASSWORD" host="lego-K53SV" id="40359a92-2c87-41df-943b-cfac73c7ea3d" port="22" nameFormat="DESCRIPTIVE" username="lego" useOpenSSHConfig="true" /> | |||
</configs> | |||
</component> | |||
</project> |
@@ -0,0 +1,14 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="WebServers"> | |||
<option name="servers"> | |||
<webServer id="1b3e9e3f-7394-4cbc-a32d-b95ef2abda52" name="backend"> | |||
<fileTransfer accessType="SFTP" host="lego-K53SV" port="22" sshConfigId="40359a92-2c87-41df-943b-cfac73c7ea3d" sshConfig="lego@lego-K53SV:22 password"> | |||
<advancedOptions> | |||
<advancedOptions dataProtectionLevel="Private" keepAliveTimeout="0" passiveMode="true" shareSSLContext="true" /> | |||
</advancedOptions> | |||
</fileTransfer> | |||
</webServer> | |||
</option> | |||
</component> | |||
</project> |
@@ -29,4 +29,4 @@ urllib3==1.26.14 | |||
Werkzeug==2.2.3 | |||
zipp==3.15.0 | |||
python-ev3dev2==2.1.0.post1 | |||
pytest | |||
pytest==7.3.1 |
@@ -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")) |
@@ -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) |
@@ -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 | |||
import logging | |||
import sys | |||
from robot import Robot | |||
# inits | |||
mydatabase = PlantDataBase(database_name=DATABASE_NAME) | |||
mydatabase.create_tables() | |||
order_handler = [] # will contain UUIDS with Order IDs | |||
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__": |
@@ -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 | |||
def delete_data(self, table_name): | |||
self.cur.execute(f'DELETE FROM {table_name}') | |||
self.conn.commit() | |||
return True | |||
except Exception as e: | |||
logging.error("Could not get measurement values: " + str(e)) | |||
# TODO: Kemals Scheiß implementieren | |||
def delete_data(self, table_name): | |||
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() |
@@ -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 |
@@ -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" | |||
} | |||