repository to manage all files related to the makeathon farm bot project (Software + Documentation).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

plantdatabase.py 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # file to create a database via python script
  2. import sqlite3
  3. from typing import Optional
  4. import logging
  5. class PlantDataBase:
  6. """
  7. Class of a PlantDataBase Object. It contains functions specifically for the plantdatabase.
  8. Usage:
  9. - First declare object
  10. - Then use create_tables() to create the tables (NECESSARY !!)
  11. - After that use the methods of this class
  12. """
  13. def __init__(self, database_name: str):
  14. """
  15. Only Constructor of the Class. Pass name of database to connect to. If not available it will create a new one.
  16. :param database_name: Name of the SQLITE database file system
  17. """
  18. self.db_file = database_name # 'backend_database.db' usually used name
  19. self.conn = None
  20. try:
  21. # connect or create new database if not available
  22. self.conn = sqlite3.connect(self.db_file, check_same_thread=False)
  23. except sqlite3.Error as e:
  24. logging.error("Database init error: " + str(e))
  25. # cursor on the database
  26. self.cur = self.conn.cursor()
  27. def create_tables(self):
  28. """
  29. Use this method to create the plants and measurement_values tables. Call this function before using the data
  30. handling methods below
  31. :return: True if successfully, False if not
  32. """
  33. try:
  34. # Create plants table if not already existing
  35. table_config = "CREATE TABLE IF NOT EXISTS plants " \
  36. "(PlantID INTEGER PRIMARY KEY," \
  37. "PlantName TEXT)"
  38. self.cur.execute(table_config)
  39. # Create measurement_values_table if not already existing
  40. table_config = "CREATE TABLE IF NOT EXISTS measurement_values " \
  41. "(measurementID INTEGER PRIMARY KEY," \
  42. "Timestamp DATETIME DEFAULT (datetime('now', 'localtime'))," \
  43. "PlantID INTEGER, " \
  44. "AirTemperature REAL," \
  45. "AirHumidity REAL," \
  46. "SoilMoisture REAL," \
  47. "Brightness REAL," \
  48. "FOREIGN KEY (PlantID)" \
  49. "REFERENCES plants (PlantID) )"
  50. self.cur.execute(table_config)
  51. return True
  52. except sqlite3.Warning as e:
  53. logging.error("Could not create tables: " + str(e))
  54. return False
  55. def insert_plant(self, plantname: str, plant_id: int) -> bool:
  56. """
  57. Insert a new plant with an id and a plantname
  58. :param plantname: name of plant
  59. :param plant_id: id of plant (position in the bed, must be unique!!)
  60. :return: True if successfully, False if not
  61. """
  62. try:
  63. self.cur.execute("INSERT INTO plants (PlantName, PlantID) VALUES (?,?)", (plantname, plant_id))
  64. self.conn.commit()
  65. return True
  66. except Exception as e:
  67. logging.error("Could not insert plant: " + str(e))
  68. return False
  69. def configure_plant(self, plant_id: int, plantname: str) -> bool:
  70. """
  71. Change a plants parameters in the database by using its PlantID as a search criteria
  72. :param plant_id: id of plant
  73. :param plantname: name of plant
  74. :return: True if successfully, False if not
  75. """
  76. try:
  77. self.cur.execute("UPDATE plants SET PlantID = ?, PlantName = ? WHERE PlantID= ?",
  78. (plant_id, plantname, plant_id))
  79. self.conn.commit()
  80. return True
  81. except Exception as e:
  82. logging.error("Could not configure plant: " + str(e))
  83. return False
  84. def delete_plant(self, plant_id):
  85. """
  86. Delete a plant from the database
  87. :param plant_id: PlantID of plant to delete
  88. :return: True if successfully, False if not
  89. """
  90. try:
  91. self.cur.execute('DELETE FROM plants WHERE PlantID = ?', (plant_id,))
  92. self.conn.commit()
  93. return True
  94. except Exception as e:
  95. logging.error("Could not delete plant: " + str(e))
  96. return False
  97. def insert_measurement_data(self, plant_id,
  98. sensordata_temp,
  99. sensordata_humidity,
  100. sensordata_soil_moisture,
  101. sensordata_brightness) -> bool:
  102. """
  103. Insert a measurement value of plantID
  104. :param plant_id: plantID of plant
  105. :param sensordata_temp: Temperature
  106. :param sensordata_humidity: Air Humidity value
  107. :param sensordata_soil_moisture: Soil Moisture value
  108. :param sensordata_brightness: brightness value
  109. :return: True if successfully, False if not
  110. """
  111. try:
  112. self.cur.execute(f"INSERT INTO measurement_values (PlantID, AirTemperature, AirHumidity,"
  113. f"SoilMoisture, Brightness) VALUES "
  114. f"({plant_id}, {sensordata_temp}, {sensordata_humidity}, {sensordata_soil_moisture}"
  115. f", {sensordata_brightness})")
  116. self.conn.commit()
  117. return True
  118. except Exception as e:
  119. logging.error("Could not insert measurement data: " + str(e))
  120. return False
  121. def get_latest_data(self, plant_name: Optional[str] = None, plant_id: Optional[int] = None):
  122. """
  123. Gets the newest parameter of specific plant and returns all parameters in json format.
  124. Either pass plant_name OR plant_id, BOTH passed -> ERROR
  125. :param plant_id: PlantID of plant
  126. :param plant_name: Name of Plant
  127. :return: JSON with data if successfully, else none
  128. """
  129. try:
  130. if plant_name is not None and plant_id is None:
  131. self.cur.execute("SELECT PlantID FROM plants where PlantName = ?", (plant_name,))
  132. plant_id = self.cur.fetchone()[0]
  133. elif (plant_id is not None and plant_name is not None) or (plant_id is None and plant_name is None):
  134. raise TypeError("Can't pass plant_id and plant_name to the function. Just one allowed !")
  135. self.cur.execute("SELECT * FROM measurement_values where PlantID = ? ORDER BY Timestamp DESC LIMIT 1",
  136. (plant_id,))
  137. data = self.cur.fetchone()
  138. json_file = {
  139. "MeasurementID": data[0],
  140. "PlantID": data[2],
  141. "Timestamp": data[1],
  142. "AirTemperature": data[3],
  143. "AirHumidity": data[4],
  144. "SoilMoisture": data[5],
  145. "Brightness": data[6],
  146. "PlantName": plant_name
  147. }
  148. return json_file
  149. except Exception as e:
  150. logging.error("Could not get measurement values: " + str(e))
  151. def delete_data(self, table_name):
  152. """
  153. Delete all data from a specific tabel
  154. :param table_name: tabel you want to delete
  155. :return: True if successfully, False if not
  156. """
  157. try:
  158. self.cur.execute(f'DELETE FROM {table_name}')
  159. self.conn.commit()
  160. return True
  161. except Exception as e:
  162. logging.error("Could not delete data: " + str(e))
  163. def plant_count(self) -> int:
  164. """
  165. returns the number of plants registered in the database
  166. :return: Count of registered plants as int
  167. """
  168. try:
  169. self.cur.execute("SELECT COUNT(*) FROM plants")
  170. return self.cur.fetchone()[0]
  171. except Exception as e:
  172. logging.error("Could not count plants: " + str(e))
  173. def get_plant_names(self) -> list:
  174. """
  175. Use this method to get a list of the Names of all registered plants
  176. :return: list containing plantNames
  177. """
  178. try:
  179. self.cur.execute("SELECT PlantName FROM plants")
  180. return self.cur.fetchall()
  181. except Exception as e:
  182. logging.error("Could not get plant names: " + str(e))
  183. def get_plant_id(self, plant_name: str) -> int:
  184. """
  185. Use this method to get the PlantID of a registered plant by its name
  186. :param plant_name: name of registered plant
  187. :return: ID of plant as int
  188. """
  189. try:
  190. self.cur.execute("SELECT PlantID FROM plants WHERE PlantName=?", (plant_name,))
  191. return self.cur.fetchone()[0]
  192. except Exception as e:
  193. logging.error("Could not get plant id: " + str(e))
  194. def __del__(self):
  195. """
  196. Destructor of Class. Disconnects from database.
  197. """
  198. self.conn.close()