NEW FILES ADDED

This commit is contained in:
caliskanbi 2023-05-10 16:04:19 +02:00
parent b8cb4f6217
commit 35118e8c20
10 changed files with 224 additions and 75 deletions

24
.idea/dataSources.xml generated
View File

@ -8,5 +8,29 @@
<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>

View File

@ -29,3 +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

Binary file not shown.

View File

@ -2,22 +2,20 @@ import random
from plantdatabase import PlantDataBase from plantdatabase import PlantDataBase
mydatabase = PlantDataBase() mydatabase = PlantDataBase('backend_database.db')
mydatabase.create_table() mydatabase.create_tables()
for i in range(1, 6): for i in range(1, 6):
mydatabase.insert_plant(_gps='gps', plantname=f"Pflanze{i}") 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, sensordata_brightness=light_intensity)
light_intensity=light_intensity)

View File

@ -6,7 +6,7 @@ Every function should return json format with the wanted data from the database
""" """
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
@ -27,8 +27,7 @@ def data_sensordata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, my
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, sensordata_brightness=payload['Brightness'])
light_intensity=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):
@ -68,23 +67,46 @@ def action_getbattery(client: mqtt.Client, userdata, message: mqtt.MQTTMessage,
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): for i in plant_names:
alldata.append(mydatabase.get_latest_data(plant_id=i)) 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 plant_data = json.loads(message.payload.decode("UTF-8"))
pass 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 plant_data = json.loads(message.payload.decode("UTF-8"))
pass 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) delete_plant = json.loads(message.payload.decode("UTF-8"))
pass 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))

View File

@ -9,13 +9,13 @@ Used protocol for interaction: mqtt (paho-mqtt module)
# 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 = PlantDataBase(database_name=DATABASE_NAME)
mydatabase.create_table() mydatabase.create_tables()
order_handler = [] # will contain UUIDS with Order IDs order_handler = [] # will contain UUIDS with Order IDs
@ -81,6 +81,10 @@ def on_connect(_client: mqtt.Client, _userdata, _flags, _rc):
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")

View File

@ -1,13 +1,15 @@
# 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)
@ -16,51 +18,85 @@ class PlantDataBase:
print(e) print(e)
self.cur = self.conn.cursor() self.cur = self.conn.cursor()
def create_table(self): def create_tables(self):
try:
table_config = "CREATE TABLE IF NOT EXISTS plants " \ table_config = "CREATE TABLE IF NOT EXISTS plants " \
"(plant_ID INTEGER PRIMARY KEY AUTOINCREMENT," \ "(PlantID INTEGER PRIMARY KEY," \
"plantName TEXT)" "PlantName TEXT)"
self.cur.execute(table_config) self.cur.execute(table_config)
table_config = "CREATE TABLE IF NOT EXISTS measurement_values " \ table_config = "CREATE TABLE IF NOT EXISTS measurement_values " \
"(measurement_id INTEGER PRIMARY KEY AUTOINCREMENT," \ "(measurementID INTEGER PRIMARY KEY," \
"Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP," \ "Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP," \
"plant_ID INTEGER, " \ "PlantID INTEGER, " \
"sensordata_temp REAL," \ "AirTemperature REAL," \
"sensordata_humidity REAL," \ "AirHumidity REAL," \
"sensordata_soil_moisture REAL," \ "SoilMoisture REAL," \
"light_intensity REAL," \ "Brightness REAL," \
"FOREIGN KEY (plant_ID)" \ "FOREIGN KEY (PlantID)" \
"REFERENCES plants (plant_ID) )" "REFERENCES plants (PlantID) )"
self.cur.execute(table_config) self.cur.execute(table_config)
return True
except sqlite3.Warning as e:
return e
def insert_plant(self, _gps: str, plantname): def insert_plant(self, plantname: str, plant_id: int):
self.cur.execute("INSERT INTO plants (gps, plantName) VALUES (?,?)", (_gps, plantname)) try:
self.cur.execute("INSERT INTO plants (PlantName, PlantID) VALUES (?,?)", (plantname, plant_id))
self.conn.commit() 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): sensordata_brightness) -> bool:
self.cur.execute(f"INSERT INTO measurement_values (plant_ID, sensordata_temp, sensordata_humidity," try:
f" sensordata_soil_moisture, light_intensity) VALUES " 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"({plant_id}, {sensordata_temp}, {sensordata_humidity}, {sensordata_soil_moisture}"
f", {light_intensity})") f", {sensordata_brightness})")
self.conn.commit() 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") 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() 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 = { json_file = {
"MeasurementID": data[0], "MeasurementID": data[0],
"PlantID": data[2], "PlantID": data[2],
@ -69,16 +105,26 @@ class PlantDataBase:
"AirHumidity": data[4], "AirHumidity": data[4],
"SoilMoisture": data[5], "SoilMoisture": data[5],
"Brightness": data[6], "Brightness": data[6],
"PlantName": name "PlantName": plant_name
} }
return json_file 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): def plant_count(self) -> int:
self.cur.execute('DELETE FROM plants WHERE plant_ID = ?', (plant_id,)) """
self.conn.commit() 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()

Binary file not shown.

View File

@ -0,0 +1,50 @@
#
# 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

View File

@ -8,6 +8,8 @@ MQTT_BROKER_LOCAL = "192.168.0.199"
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 = {
@ -21,7 +23,7 @@ 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",
@ -111,7 +113,7 @@ BATTERY = {
PLANTCOUNT = { PLANTCOUNT = {
"CurrenCount": 0, "CurrenCount": 0,
"maxCount": 0 "MaxCount": 0
} }
# endregion # endregion
@ -136,6 +138,8 @@ DELETEPLANT = {
# GETBATTERY -> no message needed # GETBATTERY -> no message needed
# GETALLDATA -> no message needed GETALLDATA = {
"PlantNames": []
}
# endregion # endregion