NEW FILES ADDED
This commit is contained in:
parent
b8cb4f6217
commit
35118e8c20
24
.idea/dataSources.xml
generated
24
.idea/dataSources.xml
generated
@ -8,5 +8,29 @@
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/software/backend/backend_database.db</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</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>
|
||||
</project>
|
@ -29,3 +29,4 @@ urllib3==1.26.14
|
||||
Werkzeug==2.2.3
|
||||
zipp==3.15.0
|
||||
python-ev3dev2==2.1.0.post1
|
||||
pytest
|
Binary file not shown.
@ -2,22 +2,20 @@ import random
|
||||
|
||||
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
|
||||
temp = random.random()
|
||||
humidity = random.random()
|
||||
soil_moisture = random.random()
|
||||
pest_infestation = 0
|
||||
light_intensity = random.random()
|
||||
mydatabase.insert_measurement_data(plant_id=plant_id,
|
||||
sensordata_temp=temp,
|
||||
sensordata_humidity=humidity,
|
||||
sensordata_soil_moisture=soil_moisture,
|
||||
pest_infestation=pest_infestation,
|
||||
light_intensity=light_intensity)
|
||||
sensordata_brightness=light_intensity)
|
@ -6,7 +6,7 @@ Every function should return json format with the wanted data from the database
|
||||
"""
|
||||
import paho.mqtt.client as mqtt
|
||||
from plantdatabase import PlantDataBase
|
||||
from software.defines import Topics
|
||||
from software.defines import Topics, MAX_PLANT_COUNT
|
||||
import json
|
||||
import uuid
|
||||
|
||||
@ -27,8 +27,7 @@ def data_sensordata(client: mqtt.Client, userdata, message: mqtt.MQTTMessage, my
|
||||
sensordata_temp=payload['AirTemperature'],
|
||||
sensordata_humidity=payload['AirHumidity'],
|
||||
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):
|
||||
@ -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):
|
||||
# TODO: get data from database
|
||||
plant_names = json.loads(message.payload.decode("UTF-8"))
|
||||
print(plant_names)
|
||||
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))
|
||||
|
||||
|
||||
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):
|
||||
# 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):
|
||||
# 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))
|
||||
|
@ -9,13 +9,13 @@ Used protocol for interaction: mqtt (paho-mqtt module)
|
||||
|
||||
# imports
|
||||
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
|
||||
import data_functions
|
||||
|
||||
# inits
|
||||
mydatabase = PlantDataBase()
|
||||
mydatabase.create_table()
|
||||
mydatabase = PlantDataBase(database_name=DATABASE_NAME)
|
||||
mydatabase.create_tables()
|
||||
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.
|
||||
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
|
||||
else:
|
||||
print("connection failed")
|
||||
|
@ -1,13 +1,15 @@
|
||||
# file to create a database via python script
|
||||
import sqlite3
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class PlantDataBase:
|
||||
"""
|
||||
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
|
||||
try:
|
||||
self.conn = sqlite3.connect(self.db_file, check_same_thread=False)
|
||||
@ -16,69 +18,113 @@ class PlantDataBase:
|
||||
print(e)
|
||||
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,
|
||||
sensordata_temp,
|
||||
sensordata_humidity,
|
||||
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
|
||||
:param plant_id:
|
||||
:param plant_name:
|
||||
: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):
|
||||
self.cur.execute(f"DELETE FROM {table_name}")
|
||||
self.cur.execute(f'DELETE FROM {table_name}')
|
||||
self.conn.commit()
|
||||
return True
|
||||
|
||||
# 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()
|
||||
|
BIN
software/backend/tests/test_database.db
Normal file
BIN
software/backend/tests/test_database.db
Normal file
Binary file not shown.
50
software/backend/tests/test_plantdatabase.py
Normal file
50
software/backend/tests/test_plantdatabase.py
Normal 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
|
@ -8,6 +8,8 @@ MQTT_BROKER_LOCAL = "192.168.0.199"
|
||||
MQTT_BROKER_GLOBAL = "mqtt.eclipseprojects.io"
|
||||
RASPI_CLIENT_ID = "smart_farming_raspi"
|
||||
BACKEND_CLIENT_ID = "smart_farming_server"
|
||||
MAX_PLANT_COUNT = 6
|
||||
DATABASE_NAME = 'backend_database.db'
|
||||
|
||||
# Topics:
|
||||
Topics = {
|
||||
@ -21,7 +23,7 @@ Topics = {
|
||||
"ROBOT_DATA_PICTURE": "ROBOT/DATA/PICTURE",
|
||||
|
||||
"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_GETBATTERY": "BACKEND/ACTION/GETBATTERY",
|
||||
"BACKEND_ACTION_GETALLDATA": "BACKEND/ACTION/GETALLDATA",
|
||||
@ -111,7 +113,7 @@ BATTERY = {
|
||||
|
||||
PLANTCOUNT = {
|
||||
"CurrenCount": 0,
|
||||
"maxCount": 0
|
||||
"MaxCount": 0
|
||||
}
|
||||
|
||||
# endregion
|
||||
@ -136,6 +138,8 @@ DELETEPLANT = {
|
||||
|
||||
# GETBATTERY -> no message needed
|
||||
|
||||
# GETALLDATA -> no message needed
|
||||
GETALLDATA = {
|
||||
"PlantNames": []
|
||||
}
|
||||
|
||||
# endregion
|
||||
|
Loading…
x
Reference in New Issue
Block a user