diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ec39be..4529f72 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,11 @@ { - "cSpell.enabled": false + "cSpell.enabled": false, + "sqltools.connections": [ + { + "previewLimit": 50, + "driver": "SQLite", + "name": "database", + "database": "${workspaceFolder:RaspberryPie}/RaspberryPie/database.db" + } + ] } \ No newline at end of file diff --git a/RaspberryPie/dataHandling.py b/RaspberryPie/dataHandling.py new file mode 100644 index 0000000..c53566b --- /dev/null +++ b/RaspberryPie/dataHandling.py @@ -0,0 +1,43 @@ +#general imports +import datetime +import sqlite3 + +# imports from Project +from RaspberryPie.logger import captScribe +from RaspberryPie.config import config + + +class BGenSecretary: + def __init__(self, database_path, image_path): + self.database = database_path + self.image_path = image_path + + def _record(self, data: dict): + connection = None + try: + connection = sqlite3.connect(self.database) + cursor = connection.cursor() + for typ in data: + time = datetime.datetime.now() + data[typ]["time_string"] = str(time) + data[typ]["unix_time"] = int(time.timestamp()) + command = "INSERT INTO {} ({}) VALUES ({})".format(typ, str([i for i in data[typ]])[1:-1], str([data[typ][i] for i in data[typ]])[1:-1]) + cursor.execute(command) + captScribe.info("Inserted data into table '{}' of database".format(typ), "BGenSecretary._record") + connection.commit() + except sqlite3.Error as e: + captScribe.error(str(e), "BGenSecretary._record") + finally: + if connection is sqlite3.Connection: + connection.close() + + def recordPicture(self, picture): + with open("{}/{}.jpg".format(self.image_path, str(datetime.datetime.now())), "w") as f: + f.write(picture) + + self._record({"picture": {"picture": picture}}) + + def recordAir(self, data): + self._record({"air": {"temperature": data[0], "humidity": data[1]}}) + +bGenSecretary = BGenSecretary(config["File Locations"]["database_file"], config["File Locations"],["image_path"]) \ No newline at end of file diff --git a/RaspberryPie/database.db b/RaspberryPie/database.db new file mode 100644 index 0000000..bd5446f Binary files /dev/null and b/RaspberryPie/database.db differ diff --git a/RaspberryPie/hardwareControl.py b/RaspberryPie/hardwareControl.py index dad7088..13599f4 100644 --- a/RaspberryPie/hardwareControl.py +++ b/RaspberryPie/hardwareControl.py @@ -10,8 +10,8 @@ import RPi.GPIO as GPIO # imports from project from RaspberryPie.config import config from RaspberryPie.logger import captScribe +from RaspberryPie.dataHandling import bGenSecretary -lib = {} class MajGenGPIOController: def __init__(self, pin_open, pin_close, delta_switchOff): @@ -60,16 +60,19 @@ class MajGenObserver: def __str__(self): return str(self.captured) - def get_picture(self): - camera = PiCamera() - majGensDictatingMachine = self.DictatingMachine() - camera.start_preview() - time.sleep(5) # letting camera adjust to environment (exposure and wb) - camera.capture(majGensDictatingMachine) - camera.stop_preview() - return str(majGensDictatingMachine) + def __init__(self, schedule_timing): + self.schedule_timing = schedule_timing - def get_sensorData(self): + def get_schedule(self): + return self.schedule_timing + +class MajGenAirChecker(MajGenObserver): + def __init__(self, schedule_timing=None): + if not schedule_timing: + schedule_timing = config["Timing"]["environmentdelta"] + super().__init__(schedule_timing) + + def execute(): sensor = Adafruit_DHT.DHT22 pin = int(config["Hardware"]["dhtpin"]) humidity, temperature = Adafruit_DHT.read_retry(sensor, pin) @@ -78,32 +81,43 @@ class MajGenObserver: humidity, temperature = (-1, -274) # if you need any numbers, why don't take impossible ones, to show error return humidity, temperature -class LtGenDataCollector: - def __init__(self, functions: dict, library, schedule_timing=None): - self.functions = functions +class MajGenVisualObserver(MajGenObserver): + def __init__(self, schedule_timing=None): if not schedule_timing: - self.schedule_timing = {"air": config["Timing"]["environmentdelta"], "camera": config["Timing"]["picturedelta"]} - else: - self.schedule_timing = schedule_timing - self.schedule = {"air": datetime.datetime.now(), "camera": datetime.datetime.now()} - self.library = library - - def get_schedule(self): - arr = [] - for event in self.schedule_timing: - arr.append(self.schedule[event]) - return arr + schedule_timing = config["Timing"]["picturedelta"] + super().__init__(schedule_timing) - def _archive(self, place, data): - pass + def execute(): + camera = PiCamera() + majGensDictatingMachine = super.DictatingMachine() + camera.start_preview() + time.sleep(5) # letting camera adjust to environment (exposure and wb) + camera.capture(majGensDictatingMachine, format="jpeg") + camera.stop_preview() + return str(majGensDictatingMachine) + +class MajGenAirRecoder(MajGenAirChecker): + def __init__(self, dataCollector, schedule_timing=None): + self.dataCollector = dataCollector + super().__init__(schedule_timing=schedule_timing) + + def execute(self): + data = super.execute() + self.dataCollector.recordeAir({"air": (str(datetime.datetime.now()), data)}) + +class MajGenVisualRecoder(MajGenVisualObserver): + def __init__(self, dataCollector, schedule_timing=None): + self.dataCollector = dataCollector + super().__init__(schedule_timing=schedule_timing) + + def execute(self): + data = super.execute() + self.dataCollector.recordePicture({"picture": (str(datetime.datetime.now()), data)}) - def collect(self, function_names: list): - time = datetime.datetime.now() - for function in function_names: - data = self.functions[function]() - self._archive(function, {time: data}) -majGenObserver = MajGenObserver() majGenGPIOController = MajGenGPIOController(config["Hardware"]["pinopen"], config["Hardware"]["pinclose"], config["Timing"]["gpioswitchoff"]) -ltGenDataCollector = LtGenDataCollector({"air": majGenObserver.get_sensorData, "picture": majGenObserver.get_picture}, lib) \ No newline at end of file +majGenVisualObserver = MajGenVisualObserver() +majGenAirChecker = MajGenAirChecker() +majGenAirRecoder = MajGenAirRecoder(bGenSecretary) +majGenVisualRecoder = MajGenVisualRecoder(bGenSecretary) diff --git a/RaspberryPie/internetHandling.py b/RaspberryPie/internetHandling.py index 232e814..82bf264 100644 --- a/RaspberryPie/internetHandling.py +++ b/RaspberryPie/internetHandling.py @@ -24,7 +24,6 @@ class MajGenApiCom: MajGenApiCom.delete_mail(id) def __init__(self, email, dropbox): - # using functions so in future, the storing can "easily" made more secure (not always stored in memory hopefully) self.email = email self.dropbox = dropbox self.mail_config = config["Mail"] diff --git a/RaspberryPie/logger.py b/RaspberryPie/logger.py index 37c5d75..d7c36e6 100644 --- a/RaspberryPie/logger.py +++ b/RaspberryPie/logger.py @@ -2,13 +2,14 @@ import logging from RaspberryPie.config import config + class CaptScribe: def __init__(self, log_info, log_error): self.logfile_info = log_info self.logfile_error = log_error self.loggers = [logging.getLogger("log_info"), logging.getLogger("log_error")] self.formatters = [logging.Formatter("%(asctime)s : %(level), %(message)s"), logging.Formatter("%(asctime)s : %(message)s: %(sinfo)")] - self.handlers = [logging.FileHandler(self.logfile_info, mode='w'), logging.FileHandler(self.logfile_error, mode='w')] + self.handlers = [logging.TimedRotatingFileHandler(self.logfile_info, when='midnight', interval=1), logging.TimedRotatingFileHandler(self.logfile_error, when='midnight', interval=1)] for i, handler in enumerate(self.handlers): handler.setFormatter(self.formatters[i]) @@ -38,4 +39,5 @@ class CaptScribe: for logger in self.loggers: logger.debug(func.upper() + ": " + msg) + captScribe = CaptScribe(config["File Locations"]["logfile_info"], config["File Locations"]["logfile_error"]) \ No newline at end of file diff --git a/RaspberryPie/raspberryPie.py b/RaspberryPie/raspberryPie.py index 48e8cd6..8dad764 100644 --- a/RaspberryPie/raspberryPie.py +++ b/RaspberryPie/raspberryPie.py @@ -10,11 +10,12 @@ Capt << BGen << MajGen << LtGen << Gen """ # imports from project from RaspberryPie.tasks import Task -from RaspberryPie.hardwareControl import majGenObserver, majGenGPIOController, ltGenDataCollector +from RaspberryPie.hardwareControl import majGenGPIOController, majGenVisualRecorder, majGenAirRecoder from RaspberryPie.config import config from RaspberryPie.logger import captScribe from RaspberryPie.internetHandling import majGenApiCom, MajGenApiCom + ltGenInterpreter, genScheduler = None tasks = [ @@ -22,11 +23,18 @@ tasks = [ Task(majGenGPIOController.close, lambda msg: 1 if ("zu" == msg.subject.lower() or "close" == msg.subject.lower()) else 0) ] + class LtGenInterpreter: - def __init__(self, tasks: list, communicator: MajGenApiCom): + def __init__(self, tasks: list, communicator: MajGenApiCom, schedule_timing=None): + if not schedule_timing: + schedule_timing = config["Timing"]["maildelta"] + self.schedule_timing self.tasks = tasks self.communicator = communicator + def get_schedule(self): + return self.schedule_timing + def execute(self): messages = self.communicator.get_emails() for message in messages: @@ -67,7 +75,23 @@ class GenScheduler: def init(): global ltGenInterpreter, genScheduler ltGenInterpreter = LtGenInterpreter(tasks, majGenApiCom) - genScheduler = GenScheduler((majGenApiCom, ltGenDataCollector)) + genScheduler = GenScheduler((ltGenInterpreter, majGenVisualRecorder, majGenAirRecoder)) + + +def main(): + suspend_shutdown = False + if genScheduler is GenScheduler: + try: + genScheduler.execute() + except Exception as e: + captScribe.critical(str(e), "main()") + if e is KeyboardInterrupt: + suspend_shutdown = True + finally: + if not suspend_shutdown: + genScheduler.initiate_shutdown() + print("The programm has finished. For more information see the log files.") init() +main() diff --git a/RaspberryPie/tasks.py b/RaspberryPie/tasks.py index a111eaa..1e2abf4 100644 --- a/RaspberryPie/tasks.py +++ b/RaspberryPie/tasks.py @@ -1,3 +1,5 @@ +from RaspberryPie.internetHandling import MajGenApiCom + class Task: def __init__(self, function, check): self.function = function