<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/software/backend/backend_database.db</jdbc-url> | <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/software/backend/backend_database.db</jdbc-url> | ||||
<working-dir>$ProjectFileDir$</working-dir> | <working-dir>$ProjectFileDir$</working-dir> | ||||
</data-source> | </data-source> | ||||
<data-source source="LOCAL" name="backend_database" uuid="4f1f9bd8-463b-4b3b-b101-cc4b9b84e2e1"> | |||||
<driver-ref>sqlite.xerial</driver-ref> | |||||
<synchronize>true</synchronize> | |||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> | |||||
<jdbc-url>jdbc:sqlite:C:\Users\bcali\Documents\Uni\BEI6\Projektarbeit\projektarbeit_duelger_waldhauser_caliskan\software\backend\tests\backend_database.db</jdbc-url> | |||||
<working-dir>$ProjectFileDir$</working-dir> | |||||
<libraries> | |||||
<library> | |||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/sqlite-jdbc-3.40.1.jar</url> | |||||
</library> | |||||
</libraries> | |||||
</data-source> | |||||
<data-source source="LOCAL" name="test_database" uuid="a72361b0-954e-42bd-8930-b14a0b4c1023"> | |||||
<driver-ref>sqlite.xerial</driver-ref> | |||||
<synchronize>true</synchronize> | |||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> | |||||
<jdbc-url>jdbc:sqlite:C:\Users\bcali\Documents\Uni\BEI6\Projektarbeit\projektarbeit_duelger_waldhauser_caliskan\software\backend\tests\test_database.db</jdbc-url> | |||||
<working-dir>$ProjectFileDir$</working-dir> | |||||
<libraries> | |||||
<library> | |||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.40.1/sqlite-jdbc-3.40.1.jar</url> | |||||
</library> | |||||
</libraries> | |||||
</data-source> | |||||
</component> | </component> | ||||
</project> | </project> |
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 |
from plantdatabase import PlantDataBase | from plantdatabase import PlantDataBase | ||||
mydatabase = PlantDataBase() | |||||
mydatabase.create_table() | |||||
mydatabase = PlantDataBase('backend_database.db') | |||||
mydatabase.create_tables() | |||||
for i in range(1,6): | |||||
mydatabase.insert_plant(_gps='gps', plantname=f"Pflanze{i}") | |||||
for i in range(1, 6): | |||||
mydatabase.insert_plant(plantname=f"Pflanze{i}") | |||||
for i in range(1,7): | |||||
for i in range(1, 7): | |||||
plant_id = i | plant_id = i | ||||
temp = random.random() | temp = random.random() | ||||
humidity = random.random() | humidity = random.random() | ||||
soil_moisture = random.random() | soil_moisture = random.random() | ||||
pest_infestation = 0 | |||||
light_intensity = random.random() | light_intensity = random.random() | ||||
mydatabase.insert_measurement_data(plant_id=plant_id, | mydatabase.insert_measurement_data(plant_id=plant_id, | ||||
sensordata_temp=temp, | sensordata_temp=temp, | ||||
sensordata_humidity=humidity, | sensordata_humidity=humidity, | ||||
sensordata_soil_moisture=soil_moisture, | sensordata_soil_moisture=soil_moisture, | ||||
pest_infestation=pest_infestation, | |||||
light_intensity=light_intensity) | |||||
sensordata_brightness=light_intensity) |
""" | """ | ||||
import paho.mqtt.client as mqtt | import paho.mqtt.client as mqtt | ||||
from plantdatabase import PlantDataBase | from plantdatabase import PlantDataBase | ||||
from software.defines import Topics | |||||
from software.defines import Topics, MAX_PLANT_COUNT | |||||
import json | import json | ||||
import uuid | import uuid | ||||
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'], | ||||
pest_infestation=0, | |||||
light_intensity=payload['Brightness']) | |||||
sensordata_brightness=payload['Brightness']) | |||||
def data_position(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | def data_position(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | ||||
def action_getalldata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | def action_getalldata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | ||||
# TODO: get data from database | |||||
plant_names = json.loads(message.payload.decode("UTF-8")) | |||||
print(plant_names) | |||||
alldata = [] | alldata = [] | ||||
for i in range(1, 7): | |||||
alldata.append(mydatabase.get_latest_data(plant_id=i)) | |||||
for i in plant_names: | |||||
alldata.append(mydatabase.get_latest_data(plant_name=i)) | |||||
client.publish(Topics['BACKEND_DATA_SENSORDATAALL'], json.dumps(alldata)) | client.publish(Topics['BACKEND_DATA_SENSORDATAALL'], json.dumps(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): | ||||
# TODO: insert new plant to database | |||||
pass | |||||
plant_data = json.loads(message.payload.decode("UTF-8")) | |||||
mydatabase.insert_plant(plantname=plant_data["PlantName"], plant_id=plant_data["PlantID"]) | |||||
mydatabase.insert_measurement_data(plant_id=plant_data["PlantID"], | |||||
sensordata_temp=plant_data["AirTemperature"], | |||||
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)) | |||||
def action_configureplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | def action_configureplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | ||||
# TODO: configure plant | |||||
pass | |||||
plant_data = json.loads(message.payload.decode("UTF-8")) | |||||
mydatabase.configure_plant(plant_id=plant_data["plant_ID"], plantname=plant_data["PlantName"]) | |||||
mydatabase.insert_measurement_data(plant_id=plant_data["PlantID"], | |||||
sensordata_temp=plant_data["AirTemperature"], | |||||
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)) | |||||
def action_deleteplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | def action_deleteplant(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | ||||
# TODO: delete plant from database (from ID) | |||||
pass | |||||
delete_plant = json.loads(message.payload.decode("UTF-8")) | |||||
mydatabase.delete_plant(plant_id=delete_plant["PlantID"]) | |||||
print("BACKEND_ACTION_DELETEPLANT RECEIVED DATA: " + str(delete_plant)) | |||||
def action_countplants(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, mydatabase: PlantDataBase): | |||||
count_payload = { | |||||
"CurrentCount": mydatabase.plant_count(), | |||||
"MaxCount": MAX_PLANT_COUNT | |||||
} | |||||
print("BACKEND_DATA_PLANTCOUNT SENDED DATA:" + str(count_payload)) | |||||
client.publish(Topics["BACKEND_ACTION_PLANTCOUNT"], json.dumps(count_payload, indent=4)) |
# imports | # imports | ||||
import paho.mqtt.client as mqtt | import paho.mqtt.client as mqtt | ||||
from software.defines import MQTT_BROKER_LOCAL, MQTT_BROKER_GLOBAL, Topics, BACKEND_CLIENT_ID | |||||
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 | ||||
# inits | # inits | ||||
mydatabase = PlantDataBase() | |||||
mydatabase.create_table() | |||||
mydatabase = PlantDataBase(database_name=DATABASE_NAME) | |||||
mydatabase.create_tables() | |||||
order_handler = [] # will contain UUIDS with Order IDs | order_handler = [] # will contain UUIDS with Order IDs | ||||
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.message_callback_add(Topics['BACKEND_ACTION_PLANTCOUNT'], lambda client, userdata, message: data_functions. | |||||
action_countplants(client, userdata, message, mydatabase)) | |||||
# END TOPIC SUBSCRIPTIONS | # END TOPIC SUBSCRIPTIONS | ||||
else: | else: | ||||
print("connection failed") | print("connection failed") |
# file to create a database via python script | # file to create a database via python script | ||||
import sqlite3 | import sqlite3 | ||||
from typing import Optional | |||||
class PlantDataBase: | class PlantDataBase: | ||||
""" | """ | ||||
Class to create Makeathon database | Class to create Makeathon database | ||||
""" | """ | ||||
def __init__(self): | |||||
self.db_file = 'backend_database.db' | |||||
def __init__(self, database_name: str): | |||||
self.db_file = database_name # 'backend_database.db' | |||||
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(e) | print(e) | ||||
self.cur = self.conn.cursor() | self.cur = self.conn.cursor() | ||||
def create_table(self): | |||||
table_config = "CREATE TABLE IF NOT EXISTS plants " \ | |||||
"(plant_ID INTEGER PRIMARY KEY AUTOINCREMENT," \ | |||||
"plantName TEXT)" | |||||
self.cur.execute(table_config) | |||||
def create_tables(self): | |||||
try: | |||||
table_config = "CREATE TABLE IF NOT EXISTS plants " \ | |||||
"(PlantID INTEGER PRIMARY KEY," \ | |||||
"PlantName TEXT)" | |||||
self.cur.execute(table_config) | |||||
table_config = "CREATE TABLE IF NOT EXISTS measurement_values " \ | |||||
"(measurement_id INTEGER PRIMARY KEY AUTOINCREMENT," \ | |||||
"Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP," \ | |||||
"plant_ID INTEGER, " \ | |||||
"sensordata_temp REAL," \ | |||||
"sensordata_humidity REAL," \ | |||||
"sensordata_soil_moisture REAL," \ | |||||
"light_intensity REAL," \ | |||||
"FOREIGN KEY (plant_ID)" \ | |||||
"REFERENCES plants (plant_ID) )" | |||||
self.cur.execute(table_config) | |||||
table_config = "CREATE TABLE IF NOT EXISTS measurement_values " \ | |||||
"(measurementID INTEGER PRIMARY KEY," \ | |||||
"Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP," \ | |||||
"PlantID INTEGER, " \ | |||||
"AirTemperature REAL," \ | |||||
"AirHumidity REAL," \ | |||||
"SoilMoisture REAL," \ | |||||
"Brightness REAL," \ | |||||
"FOREIGN KEY (PlantID)" \ | |||||
"REFERENCES plants (PlantID) )" | |||||
self.cur.execute(table_config) | |||||
return True | |||||
except sqlite3.Warning as e: | |||||
return e | |||||
def insert_plant(self, _gps: str, plantname): | |||||
self.cur.execute("INSERT INTO plants (gps, plantName) VALUES (?,?)", (_gps, plantname)) | |||||
self.conn.commit() | |||||
def insert_plant(self, plantname: str, plant_id: int): | |||||
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 | |||||
def configure_plant(self, plant_id: int, plantname: str): | |||||
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 | |||||
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 | |||||
def insert_measurement_data(self, plant_id, | def insert_measurement_data(self, plant_id, | ||||
sensordata_temp, | sensordata_temp, | ||||
sensordata_humidity, | sensordata_humidity, | ||||
sensordata_soil_moisture, | sensordata_soil_moisture, | ||||
light_intensity): | |||||
self.cur.execute(f"INSERT INTO measurement_values (plant_ID, sensordata_temp, sensordata_humidity," | |||||
f" sensordata_soil_moisture, light_intensity) VALUES " | |||||
f"({plant_id}, {sensordata_temp}, {sensordata_humidity}, {sensordata_soil_moisture}" | |||||
f", {light_intensity})") | |||||
self.conn.commit() | |||||
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})") | |||||
self.conn.commit() | |||||
return True | |||||
except (sqlite3.NotSupportedError, sqlite3.Warning) as e: | |||||
return e | |||||
def get_latest_data(self, plant_id) -> dict: | |||||
def get_latest_data(self, plant_name: Optional[str] = None, plant_id: Optional[int] = None): | |||||
""" | """ | ||||
Gets the newest parameter of specific plant and returns all parameters in json format | Gets the newest parameter of specific plant and returns all parameters in json format | ||||
:param plant_id: | :param plant_id: | ||||
:param plant_name: | |||||
:return: | :return: | ||||
""" | """ | ||||
self.cur.execute(f"SELECT * FROM measurement_values where plant_ID = {plant_id} ORDER BY Timestamp DESC LIMIT 1") | |||||
data = self.cur.fetchone() | |||||
self.cur.execute(f"SELECT plantName FROM plants where plant_ID = {plant_id}") | |||||
name = self.cur.fetchone() | |||||
print(data) | |||||
print(name[0]) | |||||
json_file = { | |||||
"MeasurementID": data[0], | |||||
"PlantID": data[2], | |||||
"Timestamp": data[1], | |||||
"AirTemperature": data[3], | |||||
"AirHumidity": data[4], | |||||
"SoilMoisture": data[5], | |||||
"Brightness": data[6], | |||||
"PlantName": name | |||||
} | |||||
return json_file | |||||
try: | |||||
if plant_name is not None and plant_id is None: | |||||
self.cur.execute("SELECT PlantID FROM plants where PlantName = ?", (plant_name,)) | |||||
plant_id = self.cur.fetchone()[0] | |||||
elif (plant_id is not None and plant_name is not None) or (plant_id is None and plant_name is None): | |||||
raise TypeError("Can't pass plant_id and plant_name to the function. Just one allowed !") | |||||
self.cur.execute("SELECT * FROM measurement_values where PlantID = ? ORDER BY Timestamp DESC LIMIT 1", | |||||
(plant_id,)) | |||||
data = self.cur.fetchone() | |||||
json_file = { | |||||
"MeasurementID": data[0], | |||||
"PlantID": data[2], | |||||
"Timestamp": data[1], | |||||
"AirTemperature": data[3], | |||||
"AirHumidity": data[4], | |||||
"SoilMoisture": data[5], | |||||
"Brightness": data[6], | |||||
"PlantName": plant_name | |||||
} | |||||
return json_file | |||||
except (sqlite3.Warning, TypeError) as e: | |||||
return e | |||||
def delete_data(self, table_name): | def delete_data(self, table_name): | ||||
self.cur.execute(f"DELETE FROM {table_name}") | |||||
self.cur.execute(f'DELETE FROM {table_name}') | |||||
self.conn.commit() | self.conn.commit() | ||||
return True | |||||
# TODO: Kemals Scheiß implementieren | # TODO: Kemals Scheiß implementieren | ||||
def delete_plant(self, plant_id): | |||||
self.cur.execute('DELETE FROM plants WHERE plant_ID = ?', (plant_id,)) | |||||
self.conn.commit() | |||||
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] | |||||
def __del__(self): | |||||
self.conn.close() |
# | |||||
# created by caliskan | |||||
# use this file to test your plantdatabase changes | |||||
from software.backend.plantdatabase import PlantDataBase | |||||
import pytest | |||||
def test_create_table(): | |||||
testdatabase = PlantDataBase(database_name='test_database.db') | |||||
assert testdatabase.create_tables() is True | |||||
def test_insert_and_delete_plant(): | |||||
testdatabase = PlantDataBase(database_name='test_database.db') | |||||
assert testdatabase.create_tables() is True | |||||
assert testdatabase.delete_data("plants") is True | |||||
assert testdatabase.insert_plant(plantname="Bertha", plant_id=1) is True | |||||
assert testdatabase.plant_count() == 1 | |||||
assert testdatabase.delete_plant(plant_id=1) is True | |||||
assert testdatabase.plant_count() == 0 | |||||
def test_insert_and_get_measurement_values(): | |||||
test_plant_id = 2 | |||||
test_temp = 22.4 | |||||
test_humidity = 93.4 | |||||
test_soil_moisture = 12.5 | |||||
test_brightness = 66 | |||||
test_plant_name = "Bertha" | |||||
testdatabase = PlantDataBase(database_name='test_database.db') | |||||
assert testdatabase.create_tables() is True | |||||
assert testdatabase.delete_data("plants") is True | |||||
assert testdatabase.insert_plant(plantname=test_plant_name, plant_id=test_plant_id) is True | |||||
assert testdatabase.insert_measurement_data(plant_id=test_plant_id, | |||||
sensordata_temp=test_temp, | |||||
sensordata_humidity=test_humidity, | |||||
sensordata_soil_moisture=test_soil_moisture, | |||||
sensordata_brightness=test_brightness) is True | |||||
test_plant_data = testdatabase.get_latest_data(plant_name=test_plant_name) | |||||
print(test_plant_data) | |||||
assert test_plant_data["PlantID"] == test_plant_id | |||||
assert test_plant_data["AirTemperature"] == test_temp | |||||
assert test_plant_data["AirHumidity"] == test_humidity | |||||
assert test_plant_data["SoilMoisture"] == test_soil_moisture | |||||
assert test_plant_data["Brightness"] == test_brightness | |||||
assert test_plant_data["PlantName"] == test_plant_name |
MQTT_BROKER_GLOBAL = "mqtt.eclipseprojects.io" | MQTT_BROKER_GLOBAL = "mqtt.eclipseprojects.io" | ||||
RASPI_CLIENT_ID = "smart_farming_raspi" | RASPI_CLIENT_ID = "smart_farming_raspi" | ||||
BACKEND_CLIENT_ID = "smart_farming_server" | BACKEND_CLIENT_ID = "smart_farming_server" | ||||
MAX_PLANT_COUNT = 6 | |||||
DATABASE_NAME = 'backend_database.db' | |||||
# Topics: | # Topics: | ||||
Topics = { | Topics = { | ||||
"ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", | "ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE", | ||||
"BACKEND_ACTION_DRIVE": "BACKEND/ACTION/DRIVE", | "BACKEND_ACTION_DRIVE": "BACKEND/ACTION/DRIVE", | ||||
"BACKEND_ACTION_DRIVEPALL": "BACKEND/ACTION/DRIVEALL", | |||||
"BACKEND_ACTION_DRIVEALL": "BACKEND/ACTION/DRIVEALL", | |||||
"BACKEND_ACTION_GETPOSITION": "BACKEND/ACTION/GETPOSITION", | "BACKEND_ACTION_GETPOSITION": "BACKEND/ACTION/GETPOSITION", | ||||
"BACKEND_ACTION_GETBATTERY": "BACKEND/ACTION/GETBATTERY", | "BACKEND_ACTION_GETBATTERY": "BACKEND/ACTION/GETBATTERY", | ||||
"BACKEND_ACTION_GETALLDATA": "BACKEND/ACTION/GETALLDATA", | "BACKEND_ACTION_GETALLDATA": "BACKEND/ACTION/GETALLDATA", | ||||
PLANTCOUNT = { | PLANTCOUNT = { | ||||
"CurrenCount": 0, | "CurrenCount": 0, | ||||
"maxCount": 0 | |||||
"MaxCount": 0 | |||||
} | } | ||||
# endregion | # endregion | ||||
# GETBATTERY -> no message needed | # GETBATTERY -> no message needed | ||||
# GETALLDATA -> no message needed | |||||
GETALLDATA = { | |||||
"PlantNames": [] | |||||
} | |||||
# endregion | # endregion |