Browse Source

NEW FILES ADDED

master
caliskanbi 1 year ago
parent
commit
35118e8c20

+ 24
- 0
.idea/dataSources.xml View File

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

+ 1
- 0
requirements.txt View File

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

BIN
software/backend/backend_database.db View File


software/backend/createdatabase_and_test.py → software/backend/createdatabase.py View File

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

+ 34
- 12
software/backend/data_functions.py 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
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))

+ 7
- 3
software/backend/main.py View File

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

+ 95
- 49
software/backend/plantdatabase.py View File

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


+ 50
- 0
software/backend/tests/test_plantdatabase.py 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

+ 7
- 3
software/defines.py View File

@@ -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…
Cancel
Save