Browse Source

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

master
caliskanbi 1 year ago
parent
commit
4e60cd9ad0

+ 14
- 0
.idea/deployment.xml View File

<?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
- 0
.idea/sshConfigs.xml View File

<?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
- 0
.idea/webServers.xml View File

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

+ 1
- 1
requirements.txt View File

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

BIN
software/backend/backend_database.db View File


+ 75
- 30
software/backend/data_functions.py View File

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):
print("message received")
# TODO: Store data in database
robot: Robot):
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):
# 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 # 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):
# 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: 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 # 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):
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))
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) action_getalldata(client, userdata, message, mydatabase)




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)




"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"))

+ 7
- 12
software/backend/dev_test_examples/mqtt_publisher.py View File

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):
client.connect(mqttBroker) client.connect(mqttBroker)


plantdata = { plantdata = {
"AirTemperature": 20.4,
"AirHumidity": 7.0,
"SoilMoisture": 5.0,
"Brightness": 39,
"PlantID": 2,
"Timestamp": "hallo",
"MeasurementID": 187
"PlantName": "Kemal"
} }


print(type(PLANTDATA)) 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)

+ 39
- 20
software/backend/main.py View File

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
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. 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:
# 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.
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.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)
_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)
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__": if __name__ == "__main__":

+ 47
- 27
software/backend/plantdatabase.py View File

# 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:
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):
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:
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: 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:
return e
except Exception as 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:
return e
except Exception as 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,
sensordata_brightness) -> bool: sensordata_brightness) -> bool:
try: try:
self.cur.execute(f"INSERT INTO measurement_values (PlantID, AirTemperature, AirHumidity," 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() self.conn.commit()
return True 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): def get_latest_data(self, plant_name: Optional[str] = None, plant_id: Optional[int] = None):
""" """
"PlantName": plant_name "PlantName": plant_name
} }
return json_file 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: 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:
""" """
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: 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): def __del__(self):
self.conn.close() self.conn.close()

+ 47
- 0
software/backend/robot.py View File

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

BIN
software/backend/tests/test_database.db View File


+ 4
- 1
software/defines.py View File

"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",
"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"


} }



Loading…
Cancel
Save