Error Handling BackEnd added, logging included, order list and robot class added

This commit is contained in:
caliskanbi 2023-05-15 10:50:19 +02:00
parent 0385aa7792
commit 4e60cd9ad0
12 changed files with 256 additions and 91 deletions

14
.idea/deployment.xml generated Normal file
View File

@ -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>

8
.idea/sshConfigs.xml generated Normal file
View File

@ -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>

14
.idea/webServers.xml generated Normal file
View File

@ -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>

View File

@ -29,4 +29,4 @@ urllib3==1.26.14
Werkzeug==2.2.3 Werkzeug==2.2.3
zipp==3.15.0 zipp==3.15.0
python-ev3dev2==2.1.0.post1 python-ev3dev2==2.1.0.post1
pytest pytest==7.3.1

Binary file not shown.

View File

@ -10,73 +10,103 @@ from software.defines import Topics, MAX_PLANT_COUNT
import json import json
import uuid import uuid
from typing import Union from typing import Union
from datetime import datetime
import logging
from robot import Robot
# Robot Channel Reactions # Robot Channel Reactions
def data_sensordata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase, def data_sensordata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase,
order_handler: list): robot: Robot):
print("message received")
# TODO: Store data in database
str_in = str(message.payload.decode("UTF-8")) str_in = str(message.payload.decode("UTF-8"))
payload = json.loads(str_in) 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'], mydatabase.insert_measurement_data(plant_id=payload['PlantID'],
sensordata_temp=payload['AirTemperature'], sensordata_temp=payload['AirTemperature'],
sensordata_humidity=payload['AirHumidity'], sensordata_humidity=payload['AirHumidity'],
sensordata_soil_moisture=payload['SoilMoisture'], sensordata_soil_moisture=payload['SoilMoisture'],
sensordata_brightness=payload['Brightness']) 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): def data_position(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot):
# TODO: Forward to frontend in json format logging.info("ROBOT_DATA_POSITION Received data: " + json.dumps(message.payload.decode("UTF-8")))
client.publish(Topics['BACKEND_DATA_POSITION'], 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): def data_battery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, robot: Robot):
# TODO: Forward to frontend in json format logging.info("ROBOT_DATA_BATTERY Received data: " + json.dumps(message.payload.decode("UTF-8")))
client.publish(Topics['BACKEND_DATA_BATTERY'], 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 # FrontEnd Channel Reactions
def action_drive(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase, def action_drive(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase,
order_handler: list): robot: Robot):
# TODO: ROBOT READY CHECK plant_id = mydatabase.get_plant_id(plant_name=json.loads(message.payload.decode("UTF-8"))["PlantName"])
if len(order_handler) < 5: action_id = str(uuid.uuid4())
order_handler.append(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: else:
# TODO: What to do when no place in order_list left if robot.get_order_number() < 5:
pass robot.add_order(drive_data)
client.publish(Topics['ROBOT_ACTION_DRIVE'], message.payload.decode("utf-8")) 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 # TODO: Implement here
pass print("HELLO")
def action_getposition(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): def action_getposition(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase):
client.publish(Topics['ROBOT_ACTION_GETPOSITION']) 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']) 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): def action_getalldata(client: mqtt.Client, userdata, message: Union[mqtt.MQTTMessage, list], mydatabase: PlantDataBase):
plant_names = mydatabase.get_plant_names() plant_names = mydatabase.get_plant_names()
print(type(plant_names))
alldata = [] alldata = []
for i in plant_names: 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])) alldata.append(mydatabase.get_latest_data(plant_name=i[0]))
client.publish(Topics['BACKEND_DATA_SENSORDATAALL'], json.dumps(alldata)) 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): 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_humidity=plant_data["AirHumidity"],
sensordata_soil_moisture=plant_data["SoilMoisture"], sensordata_soil_moisture=plant_data["SoilMoisture"],
sensordata_brightness=plant_data["Brightness"]) sensordata_brightness=plant_data["Brightness"])
print("BACKEND_ACTION_NEWPLANT RECEIVED DATA: " + str(plant_data)) logging.info("BACKEND_ACTION_NEWPLANT new plant data received and inserted: " + str(plant_data))
print(mydatabase.get_plant_names())
action_getalldata(client, userdata, message, mydatabase) 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_humidity=plant_data["AirHumidity"],
sensordata_soil_moisture=plant_data["SoilMoisture"], sensordata_soil_moisture=plant_data["SoilMoisture"],
sensordata_brightness=plant_data["Brightness"]) 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) action_getalldata(client, userdata, message, mydatabase)
def action_deleteplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): def action_deleteplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase):
delete_plant = json.loads(message.payload.decode("UTF-8")) delete_plant = json.loads(message.payload.decode("UTF-8"))
mydatabase.delete_plant(plant_id=delete_plant) 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) action_getalldata(client, userdata, message, mydatabase)
@ -118,4 +147,20 @@ def action_countplants(client: mqtt.Client, userdata, message: mqtt.MQTTMessage,
"MaxCount": MAX_PLANT_COUNT "MaxCount": MAX_PLANT_COUNT
} }
client.publish(Topics["BACKEND_DATA_PLANTCOUNT"], json.dumps(count_payload)) 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"))

View File

@ -1,10 +1,12 @@
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
import software.defines
from software.defines import MQTT_BROKER_LOCAL from software.defines import MQTT_BROKER_LOCAL
from random import randrange, uniform from random import randrange, uniform
import time import time
import json import json
from software.defines import Topics, PLANTDATA from software.defines import Topics, PLANTDATA
mqttBroker = "192.168.178.182" mqttBroker = software.defines.MQTT_BROKER_GLOBAL
def on_connect(client, userdata, flags, rc): def on_connect(client, userdata, flags, rc):
@ -20,17 +22,10 @@ client.on_connect = on_connect
client.connect(mqttBroker) client.connect(mqttBroker)
plantdata = { plantdata = {
"AirTemperature": 20.4, "PlantName": "Kemal"
"AirHumidity": 7.0,
"SoilMoisture": 5.0,
"Brightness": 39,
"PlantID": 2,
"Timestamp": "hallo",
"MeasurementID": 187
} }
print(type(PLANTDATA)) print(type(PLANTDATA))
while True: client.publish("BACKEND/ACTION/GETBATTERY", json.dumps(plantdata))
client.publish("TEST", json.dumps(plantdata))
print(json.dumps(plantdata)) print(json.dumps(plantdata))
time.sleep(2) time.sleep(2)

View File

@ -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 software.defines import MQTT_BROKER_LOCAL, MQTT_BROKER_GLOBAL, Topics, BACKEND_CLIENT_ID, DATABASE_NAME
from plantdatabase import PlantDataBase from plantdatabase import PlantDataBase
import data_functions import data_functions
import logging
# inits import sys
mydatabase = PlantDataBase(database_name=DATABASE_NAME) from robot import Robot
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. This method gets called, when it connects to a mqtt broker.
It is used to subscribe to the specific topics It is used to subscribe to the specific topics
:param _robot:
:param _mydatabase:
:param _client: mqtt client object :param _client: mqtt client object
:param _userdata: :param _userdata:
:param _flags: :param _flags:
@ -37,25 +37,25 @@ def on_connect(_client: mqtt.Client, _userdata, _flags, _rc):
# From Robot: # From Robot:
_client.subscribe(Topics['ROBOT_DATA_SENSORDATA']) _client.subscribe(Topics['ROBOT_DATA_SENSORDATA'])
_client.message_callback_add(Topics['ROBOT_DATA_SENSORDATA'], lambda client, userdata, message: data_functions. _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.subscribe(Topics['ROBOT_DATA_POSITION'])
_client.message_callback_add(Topics['ROBOT_DATA_POSITION'], data_functions.data_position) _client.message_callback_add(Topics['ROBOT_DATA_POSITION'], data_functions.data_position)
_client.subscribe(Topics['ROBOT_DATA_BATTERY']) _client.subscribe(Topics['ROBOT_DATA_BATTERY'])
_client.message_callback_add(Topics['ROBOT_DATA_BATTERY'], lambda client, userdata, message: data_functions. _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') # client.subscribe('Robot/Data/Picture')
# From FrontEnd: # From FrontEnd:
_client.subscribe(Topics['BACKEND_ACTION_DRIVE']) _client.subscribe(Topics['BACKEND_ACTION_DRIVE'])
_client.message_callback_add(Topics['BACKEND_ACTION_DRIVE'], lambda client, userdata, message: data_functions. _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.subscribe(Topics['BACKEND_ACTION_DRIVEALL'])
_client.message_callback_add(Topics['BACKEND_ACTION_DRIVE'], lambda client, userdata, message: data_functions. _client.message_callback_add(Topics['BACKEND_ACTION_DRIVEALL'], lambda client, userdata, message: data_functions.
action_driveall(client, userdata, message, mydatabase)) action_driveall(client, userdata, message, _mydatabase, _robot))
_client.subscribe(Topics['BACKEND_ACTION_GETPOSITION']) _client.subscribe(Topics['BACKEND_ACTION_GETPOSITION'])
_client.message_callback_add(Topics['BACKEND_ACTION_GETPOSITION'], data_functions.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.subscribe(Topics['BACKEND_ACTION_GETALLDATA'])
_client.message_callback_add(Topics['BACKEND_ACTION_GETALLDATA'], _client.message_callback_add(Topics['BACKEND_ACTION_GETALLDATA'],
lambda client, userdata, message: data_functions. 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.subscribe(Topics['BACKEND_ACTION_NEWPLANT'])
_client.message_callback_add(Topics['BACKEND_ACTION_NEWPLANT'], lambda client, userdata, message: data_functions. _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.subscribe(Topics['BACKEND_ACTION_CONFIGUREPLANT'])
_client.message_callback_add(Topics['BACKEND_ACTION_CONFIGUREPLANT'], lambda client, userdata, message: data_functions. _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.subscribe(Topics['BACKEND_ACTION_DELETEPLANT'])
_client.message_callback_add(Topics['BACKEND_ACTION_DELETEPLANT'], _client.message_callback_add(Topics['BACKEND_ACTION_DELETEPLANT'],
lambda client, userdata, message: data_functions. 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.subscribe(Topics['BACKEND_ACTION_PLANTCOUNT'])
_client.message_callback_add(Topics['BACKEND_ACTION_PLANTCOUNT'], lambda client, userdata, message: data_functions. _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 # END TOPIC SUBSCRIPTIONS
else: else:
print("connection failed") print("connection failed")
def main(): def main():
client = mqtt.Client(BACKEND_CLIENT_ID) robot = Robot()
client.on_connect = on_connect my_database = PlantDataBase(database_name=DATABASE_NAME)
client.connect(MQTT_BROKER_GLOBAL) my_database.create_tables()
client.loop_forever() 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__": if __name__ == "__main__":

View File

@ -1,6 +1,7 @@
# file to create a database via python script # file to create a database via python script
import sqlite3 import sqlite3
from typing import Optional from typing import Optional
import logging
class PlantDataBase: class PlantDataBase:
@ -13,9 +14,8 @@ class PlantDataBase:
self.conn = None self.conn = None
try: try:
self.conn = sqlite3.connect(self.db_file, check_same_thread=False) self.conn = sqlite3.connect(self.db_file, check_same_thread=False)
print(sqlite3.version)
except sqlite3.Error as e: except sqlite3.Error as e:
print(e) logging.error("Database init error: " + str(e))
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
def create_tables(self): def create_tables(self):
@ -38,32 +38,36 @@ class PlantDataBase:
self.cur.execute(table_config) self.cur.execute(table_config)
return True return True
except sqlite3.Warning as e: 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: try:
self.cur.execute("INSERT INTO plants (PlantName, PlantID) VALUES (?,?)", (plantname, plant_id)) self.cur.execute("INSERT INTO plants (PlantName, PlantID) VALUES (?,?)", (plantname, plant_id))
self.conn.commit() self.conn.commit()
return True return True
except (sqlite3.NotSupportedError, sqlite3.Warning) as e: except Exception as e:
return 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: try:
self.cur.execute("UPDATE plants SET PlantID = ?, PlantName = ? WHERE PlantID= ?", self.cur.execute("UPDATE plants SET PlantID = ?, PlantName = ? WHERE PlantID= ?",
(plant_id, plantname, plant_id)) (plant_id, plantname, plant_id))
self.conn.commit() self.conn.commit()
return True return True
except (sqlite3.NotSupportedError, sqlite3.Warning) as e: except Exception as e:
return e logging.error("Could not configure plant: " + str(e))
return False
def delete_plant(self, plant_id): def delete_plant(self, plant_id):
try: try:
self.cur.execute('DELETE FROM plants WHERE PlantID = ?', (plant_id,)) self.cur.execute('DELETE FROM plants WHERE PlantID = ?', (plant_id,))
self.conn.commit() self.conn.commit()
return True return True
except (sqlite3.NotSupportedError, sqlite3.Warning) as e: except Exception as e:
return e logging.error("Could not delete plant: " + str(e))
return False
def insert_measurement_data(self, plant_id, def insert_measurement_data(self, plant_id,
sensordata_temp, sensordata_temp,
@ -77,8 +81,9 @@ class PlantDataBase:
f", {sensordata_brightness})") f", {sensordata_brightness})")
self.conn.commit() self.conn.commit()
return True return True
except (sqlite3.NotSupportedError, sqlite3.Warning) as e: except Exception as e:
return 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): def get_latest_data(self, plant_name: Optional[str] = None, plant_id: Optional[int] = None):
""" """
@ -108,27 +113,42 @@ class PlantDataBase:
"PlantName": plant_name "PlantName": plant_name
} }
return json_file 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): def delete_data(self, table_name):
try:
self.cur.execute(f'DELETE FROM {table_name}') self.cur.execute(f'DELETE FROM {table_name}')
self.conn.commit() self.conn.commit()
return True return True
except Exception as e:
# TODO: Kemals Scheiß implementieren logging.error("Could not delete data: " + str(e))
def plant_count(self) -> int: def plant_count(self) -> int:
""" """
returns the number of plants registered in the database returns the number of plants registered in the database
:return: :return:
""" """
try:
self.cur.execute("SELECT COUNT(*) FROM plants") self.cur.execute("SELECT COUNT(*) FROM plants")
return self.cur.fetchone()[0] return self.cur.fetchone()[0]
except Exception as e:
logging.error("Could not count plants: " + str(e))
def get_plant_names(self) -> list: def get_plant_names(self) -> list:
try:
self.cur.execute("SELECT PlantName FROM plants") self.cur.execute("SELECT PlantName FROM plants")
return self.cur.fetchall() 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): def __del__(self):
self.conn.close() self.conn.close()

47
software/backend/robot.py Normal file
View File

@ -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

View File

@ -21,6 +21,8 @@ Topics = {
"ROBOT_DATA_BATTERY": "ROBOT/DATA/BATTERY", "ROBOT_DATA_BATTERY": "ROBOT/DATA/BATTERY",
"ROBOT_DATA_POSITION": "ROBOT/DATA/POSITION", "ROBOT_DATA_POSITION": "ROBOT/DATA/POSITION",
"ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", "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_DRIVE": "BACKEND/ACTION/DRIVE",
"BACKEND_ACTION_DRIVEALL": "BACKEND/ACTION/DRIVEALL", "BACKEND_ACTION_DRIVEALL": "BACKEND/ACTION/DRIVEALL",
@ -38,7 +40,8 @@ Topics = {
"BACKEND_DATA_BATTERY": "BACKEND/DATA/BATTERY", "BACKEND_DATA_BATTERY": "BACKEND/DATA/BATTERY",
"BACKEND_DATA_PICTURE": "BACKEND/DATA/PICTURE", "BACKEND_DATA_PICTURE": "BACKEND/DATA/PICTURE",
"BACKEND_DATA_PLANTCOUNT": "BACKEND/DATA/PLANTCOUNT", "BACKEND_DATA_PLANTCOUNT": "BACKEND/DATA/PLANTCOUNT",
"BACKEND_DATA_ERROR": "BACKEND/DATA/ERROR",
"BACKEND_DATA_ROBOTREADY": "BACKEND/DATA/ROBOTREADY"
} }