diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 6672172..ea872fb 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.1.4 +current_version = 0.1.5 commit = True tag = True diff --git a/setup.py b/setup.py index 6924516..f5c62d6 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open('README.rst') as f: setuptools.setup( name='TSGRain Controller', - version='0.1.4', + version='0.1.5', author='ThetaDev', description='TSGRain irrigation controller', long_description=README, diff --git a/tests/test_application.py b/tests/test_application.py index 2286230..9ef4413 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -45,7 +45,7 @@ def app(mocker): assert not app.is_running() -def test_start_task(app): +def test_request_task(app): # Manually start a task (like via button press) res = app.request_task( models.TaskRequest(source=models.Source.MANUAL, @@ -80,13 +80,13 @@ def test_start_task(app): assert res.stopped -def test_start_task_queue(app): - # Manually start a task (like via button press) +def test_request_task_queue(app): + # Enqueue and start a new task res = app.request_task( models.TaskRequest(source=models.Source.MANUAL, zone_id=2, duration=30, - queuing=False, + queuing=True, cancelling=True)) assert res.started assert not res.stopped @@ -135,6 +135,51 @@ def test_start_task_queue(app): assert res.stopped +def test_start_task(app): + # Manually start a task (like via button press) + assert app.start_task(models.Source.MANUAL, 2, 30, False) + + # Queue processing time + time.sleep(0.1) + + # Try to start the same task again -> nothing happens + assert not app.start_task(models.Source.MANUAL, 2, 30, False) + + +def test_start_task_queue(app): + # Enqueue and start a new task + assert app.start_task(models.Source.MANUAL, 2, 30, True) + + # Queue processing time + time.sleep(0.1) + assert app.queue.running_task.zone_id == 2 + + # Duplicate task should not be enqueued + assert not app.start_task(models.Source.MANUAL, 2, 30, True) + + # Enqueue new tasks + assert app.start_task(models.Source.MANUAL, 3, 30, True) + assert app.start_task(models.Source.SCHEDULE, 2, 30, True) + + +def test_stop_task(app): + # Enqueue and start a new task + assert app.start_task(models.Source.MANUAL, 2, 30, True) + + # Queue processing time + time.sleep(0.1) + assert app.queue.running_task.zone_id == 2 + + # Stop task + assert not app.stop_task(models.Source.MANUAL, 3) + assert app.stop_task(models.Source.MANUAL, 2) + + # Queue processing time + time.sleep(0.1) + + assert app.queue.running_task is None + + def test_crud_job(app): # Insert jobs job1 = models.Job.deserialize(JOB1_DATA) diff --git a/tsgrain_controller/__init__.py b/tsgrain_controller/__init__.py index 7525d19..66a87bb 100644 --- a/tsgrain_controller/__init__.py +++ b/tsgrain_controller/__init__.py @@ -1 +1 @@ -__version__ = '0.1.4' +__version__ = '0.1.5' diff --git a/tsgrain_controller/application.py b/tsgrain_controller/application.py index 9719bbf..5239347 100644 --- a/tsgrain_controller/application.py +++ b/tsgrain_controller/application.py @@ -121,7 +121,7 @@ class Application(models.AppInterface): task = models.Task(source, zone_id, duration) task.validate(self) - return self.queue.enqueue(task, not queuing) + return self.queue.enqueue(task, queuing) def stop_task(self, source: models.Source, zone_id: int) -> bool: for task in self.queue.tasks: @@ -176,6 +176,7 @@ class Application(models.AppInterface): systimecfg.set_system_timezone(tz, self.cfg.cmd_set_timezone) def start(self): + """Starte die Anwendung""" logging.info('Starting application') self._running = True self.io.start() @@ -185,6 +186,7 @@ class Application(models.AppInterface): self.grpc_server.start() def stop(self): + """Stoppe die Anwendung""" logging.info('Stopping application') self._running = False self.grpc_server.stop(None) diff --git a/tsgrain_controller/io/mcp23017.py b/tsgrain_controller/io/mcp23017.py index 61d9b53..a5df844 100644 --- a/tsgrain_controller/io/mcp23017.py +++ b/tsgrain_controller/io/mcp23017.py @@ -238,7 +238,7 @@ class _MCP23017Device: Beispiel: ``0x27/B0`` (MCP23017 mit I2C-Adresse 0x27, Pin B0) Um den Zustand eines Geräts zu invertieren, einfach ``/!`` - an den Konfiguraionsstring anfügen: ``0x27/B0/!`` + an den Konfigurationsstring anfügen: ``0x27/B0/!`` :param cfg_str: Konfigurationsstring :return: Neues ``_MCP23017Device``-Objekt diff --git a/tsgrain_controller/models.py b/tsgrain_controller/models.py index 360f47a..71627cf 100644 --- a/tsgrain_controller/models.py +++ b/tsgrain_controller/models.py @@ -51,10 +51,10 @@ class Job: and date_now.minute == self.date.minute return date_now.year == self.date.year \ - and date_now.month == self.date.month \ - and date_now.day == self.date.day \ - and date_now.hour == self.date.hour \ - and date_now.minute == self.date.minute + and date_now.month == self.date.month \ + and date_now.day == self.date.day \ + and date_now.hour == self.date.hour \ + and date_now.minute == self.date.minute def serialize(self) -> Dict[str, Any]: return { @@ -96,6 +96,10 @@ class Job: ) def validate(self, app: 'AppInterface'): + """ + Prüfe, ob der Task gültige Daten enthält + (Zonen existieren, Bewässerungszeit > 0) + """ if not self.zones: raise util.InvalidInputException('No zones set') if self.duration < 1: @@ -309,7 +313,7 @@ class AppInterface: :param request: Objekt, dass die Parameter der neuen Aufgabe enthält. :return: Statusobjekt (Information, ob eine Aufgabe gestartet oder gestoppt - wurde). + wurde). """ def start_task(self, source: Source, zone_id: int, duration: int, @@ -321,7 +325,7 @@ class AppInterface: :param zone_id: ID der Bewässerungszone :param duration: Bewässerungsdauer in Sekunden (0 für Standarddauer) :param queuing: Neue Aufgabe in die Warteschlange einreihen, wenn momentan - eine andere Zone bewässert wird. + eine andere Zone bewässert wird. :return: True wenn die Aufgabe erfolgreich gestartet wurde """ diff --git a/tsgrain_controller/task_queue.py b/tsgrain_controller/task_queue.py index 6b50f76..dab7b04 100644 --- a/tsgrain_controller/task_queue.py +++ b/tsgrain_controller/task_queue.py @@ -28,7 +28,7 @@ class TaskQueue(util.StoppableThread, TaskHolder): :param task: Neuer Task :param queuing: Füge Task der Warteschlange hinzu, wenn bereits - ein anderer Task läuft + ein anderer Task läuft :return: True wenn Task erfolgreich hinzugefügt """ if not queuing and self.running_task is not None: diff --git a/tsgrain_controller/util.py b/tsgrain_controller/util.py index bb63b9a..5e04804 100644 --- a/tsgrain_controller/util.py +++ b/tsgrain_controller/util.py @@ -129,9 +129,20 @@ class StoppableThread(threading.Thread): pass def run_cycle(self): - pass + """ + Führe einen Durchlauf des Threads aus. + + Diese Funktion darf nicht blockieren, sonst kann der + Thread nicht gestoppt werden. + """ def run(self): + """ + Führe die ``run_cycle()``-Funktion in + Endlosschleife aus, mit einer durch das + ``interval``-Attribut bestimmten Verzögerung zwischen + den Durchläufen. + """ try: self.setup() @@ -146,6 +157,10 @@ class StoppableThread(threading.Thread): sys.excepthook(*sys.exc_info()) def stop(self): + """ + Stoppe den Thread und warte bis er beendet. Dies dauert + maximal ``interval`` + Durchlaufzeit von ``run_cycle()``. + """ self._stop_signal.set() try: self.join()