From 2013c2cf411584889d0c876594669daa2b7a6735 Mon Sep 17 00:00:00 2001 From: Kerboul Date: Sun, 27 Apr 2025 17:06:55 +0200 Subject: [PATCH] =?UTF-8?q?Am=C3=A9liorer=20la=20gestion=20des=20configura?= =?UTF-8?q?tions=20et=20des=20captures=20dans=20les=20scripts=20de=20timel?= =?UTF-8?q?apse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Automate.py | 97 ++++++++++++++++++++++++++++++----------- sync_offline_data.py | 36 ++++++++++++++- timelapse/api_client.py | 22 +++++++++- timelapse/capture.py | 53 +++++++++++++++++++--- timelapse_offline.py | 39 ++++++++++++----- timelapse_online.py | 28 +++++++++++- 6 files changed, 230 insertions(+), 45 deletions(-) diff --git a/Automate.py b/Automate.py index 7f511a1..9999404 100644 --- a/Automate.py +++ b/Automate.py @@ -26,43 +26,90 @@ def main(): # Récupérer le statut de la caméra depuis l'API camera_status = api_client.get_camera_status() - if camera_status is None: - logging.error("Impossible d'obtenir le statut de la caméra depuis l'API") - return - - # Mettre à jour la configuration locale - api_client.update_camera_config(camera_status) + # Vérifier si la configuration actuelle est déjà active et non terminée + is_active_config = config.get("config_active", False) + images_remaining = config.get("nb_images_restantes", 0) - # Vérifier l'état de maintenance + if camera_status is None: + logging.warning("Impossible d'obtenir le statut de la caméra depuis l'API") + if is_active_config and images_remaining > 0: + logging.info("Utilisation de la configuration locale existante") + return + logging.info("Aucune configuration active et impossibilité de récupérer le statut") + return + + # Vérifier l'état de maintenance en priorité if camera_status.get("maintenance", False): logging.info("Caméra en mode maintenance, aucune action nécessaire") + # Mettre à jour la configuration pour refléter le mode maintenance + config.update_config({"maintenance": True, "config_active": False}) return # Vérifier si un arrêt de la procédure est demandé if camera_status.get("stop_flag", False): logging.info("Arrêt de la procédure en cours...") - # Supprimer le fichier de configuration s'il existe - config.delete_config_file() + # Réinitialiser les configurations actives + config.update_config({ + "config_active": False, + "nb_images_restantes": 0, + "stop_current_config": True + }) + + # Confirmer l'arrêt au serveur + confirmed = api_client.confirm_stop() + if confirmed: + logging.info("Arrêt confirmé au serveur") + else: + logging.warning("Échec de la confirmation d'arrêt au serveur") + + # Configuration d'un redémarrage régulier pour vérifier les nouvelles configurations + config.set("restart_interval", 120) # 2 minutes - # Confirmer l'arrêt - api_client.confirm_stop() return - # Vérifier s'il y a une configuration à appliquer - if not camera_status.get("idle", True): - logging.info("Configuration active détectée") - - # Obtenir les paramètres - interval = camera_status.get("interval", 3) - - # Envoyer l'intervalle au microcontrôleur - logging.info(f"Envoi de l'intervalle au microcontrôleur: {interval}s") - micro_controller.send_interval(interval) - - # Éteindre le système après configuration - logging.info("Configuration terminée, arrêt du système") - subprocess.run(["sudo", "shutdown", "now"]) + # Vérifier si le système est en IDLE et si une configuration est déjà active + is_idle = camera_status.get("idle", True) + + if is_idle: + logging.info("Système en mode IDLE") + if is_active_config: + # Si le nombre d'images est atteint, désactiver la configuration + if images_remaining <= 0: + logging.info("Configuration terminée: nombre d'images atteint") + config.update_config({"config_active": False}) + else: + logging.info(f"Configuration active: il reste {images_remaining} images à capturer") + else: + logging.info("Aucune configuration active, attente en mode IDLE") + # Configuration d'un redémarrage régulier pour vérifier les nouvelles configurations + config.set("restart_interval", 120) # 2 minutes + return + + # Si on arrive ici, il y a une nouvelle configuration à appliquer + logging.info("Nouvelle configuration active détectée") + + # Mettre à jour la configuration locale + config_update = { + "config_active": True, + "maintenance": False, + "timelapse": camera_status.get("interval", 3), + "conf_nb_images": camera_status.get("nb_images", 1), + "nb_images_restantes": camera_status.get("nb_images", 1), + "stop_current_config": False, + "idle": is_idle + } + + config.update_config(config_update) + + # Envoyer l'intervalle au microcontrôleur + interval = camera_status.get("interval", 3) + logging.info(f"Envoi de l'intervalle au microcontrôleur: {interval}s") + micro_controller.send_interval(interval) + + # Éteindre le système après configuration (mais ne pas arrêter en prod) + # logging.info("Configuration terminée, arrêt du système") + # subprocess.run(["sudo", "shutdown", "now"]) except Exception as e: logging.error(f"Erreur dans le script d'automatisation: {e}") diff --git a/sync_offline_data.py b/sync_offline_data.py index 2f83e60..31a90ab 100644 --- a/sync_offline_data.py +++ b/sync_offline_data.py @@ -9,8 +9,10 @@ Remplace l'ancien Send_data_stocked.py import os import sys import logging +import time from timelapse.config import config from timelapse.capture import timelapse_manager +from timelapse.api_client import api_client def main(): @@ -21,14 +23,46 @@ def main(): logging.info("Démarrage de la synchronisation des données hors ligne") try: + # Vérifier la connexion au serveur + camera_status = api_client.get_camera_status() + if camera_status is None: + logging.error("Impossible de se connecter au serveur. Synchronisation reportée.") + sys.exit(1) + + # Vérifier si le système est en maintenance + if camera_status.get("maintenance", False): + logging.info("Caméra en mode maintenance, aucune synchronisation effectuée") + sys.exit(0) + # Synchroniser les captures hors ligne + start_time = time.time() sync_count = timelapse_manager.sync_offline_captures() + duration = time.time() - start_time if sync_count > 0: - logging.info(f"Synchronisation réussie de {sync_count} captures") + logging.info(f"Synchronisation réussie de {sync_count} captures en {duration:.2f} secondes") + + # Vérifier s'il reste des images à synchroniser + remaining_offline = timelapse_manager.count_offline_captures() + if remaining_offline > 0: + logging.info(f"Il reste encore {remaining_offline} captures à synchroniser") + else: + logging.info("Toutes les captures hors ligne ont été synchronisées") else: logging.info("Aucune capture à synchroniser") + # Vérifier si un arrêt est demandé + if camera_status.get("stop_flag", False): + logging.info("Demande d'arrêt détectée, confirmation au serveur") + api_client.confirm_stop() + + # Réinitialiser l'état actif + config.update_config({ + "config_active": False, + "nb_images_restantes": 0, + "stop_current_config": True + }) + except Exception as e: logging.error(f"Erreur lors de la synchronisation des données: {e}") sys.exit(1) diff --git a/timelapse/api_client.py b/timelapse/api_client.py index 72393e5..a810e5f 100644 --- a/timelapse/api_client.py +++ b/timelapse/api_client.py @@ -95,17 +95,35 @@ class APIClient: return False try: + # Récupérer l'état actuel pour comparaison + is_currently_active = config.get("config_active", False) + current_nb_images = config.get("conf_nb_images", 0) + + # Vérifier si c'est une nouvelle configuration + is_new_config = (not is_currently_active and not status.get("idle", True)) + + # Préparer la mise à jour config_update = { "maintenance": status.get("maintenance", False), "timelapse": status.get("interval", 3), "conf_nb_images": status.get("nb_images", 1), - "nb_images_restantes": status.get("nb_images", 1), - "set_config": status.get("idle", False), + "idle": status.get("idle", True), "stop_current_config": status.get("stop_flag", False) } + # Ne mettre à jour le nombre d'images restantes que pour une nouvelle configuration + # ou si la configuration est réinitialisée + if is_new_config or status.get("stop_flag", False): + config_update["nb_images_restantes"] = status.get("nb_images", 1) + config_update["config_active"] = not status.get("idle", True) + + if is_new_config: + logging.info(f"Nouvelle configuration: {status.get('nb_images', 1)} images à capturer") + + # Mise à jour de la configuration config.update_config(config_update) logging.info("Configuration mise à jour depuis l'API") + return True except Exception as e: diff --git a/timelapse/capture.py b/timelapse/capture.py index 5828741..c7ec81c 100644 --- a/timelapse/capture.py +++ b/timelapse/capture.py @@ -167,21 +167,62 @@ class TimelapseCaptureManager: Args: online: Si la caméra est connectée au serveur + + Returns: + bool: True si la séquence est terminée (toutes les images capturées), False sinon """ + # Vérifier si la configuration est active + is_active = config.get("config_active", False) + is_stopped = config.get("stop_current_config", False) + + if not is_active or is_stopped: + logging.info("Aucune configuration active ou configuration arrêtée") + return True + # Vérifier si des images sont restantes à capturer remaining_images = config.get("nb_images_restantes", 0) - if remaining_images > 0: - logging.info(f"Démarrage d'une séquence de capture ({remaining_images} images restantes)") - - # Capturer une image - self.single_capture(online) + if remaining_images <= 0: + logging.info("Toutes les images ont été capturées") + # Désactiver la configuration active + config.update_config({"config_active": False}) + return True + logging.info(f"Démarrage d'une séquence de capture ({remaining_images} images restantes)") + + # Capturer une image + result = self.single_capture(online) + + if result: # Décrémenter le compteur d'images restantes remaining_images = config.decrement_remaining_images() logging.info(f"Images restantes: {remaining_images}") + + # Vérifier si c'était la dernière image + if remaining_images <= 0: + logging.info("Toutes les images ont été capturées") + # Désactiver la configuration active + config.update_config({"config_active": False}) + return True else: - logging.info("Aucune image restante à capturer") + logging.error("Échec de la séquence de capture") + + return False + + def count_offline_captures(self): + """ + Compte le nombre de captures hors ligne en attente de synchronisation. + + Returns: + int: Nombre de captures hors ligne + """ + if not os.path.exists(self.offline_dir): + return 0 + + offline_dirs = [d for d in os.listdir(self.offline_dir) + if os.path.isdir(os.path.join(self.offline_dir, d))] + + return len(offline_dirs) # Instance globale du gestionnaire de capture diff --git a/timelapse_offline.py b/timelapse_offline.py index 06a3d06..295b3c4 100644 --- a/timelapse_offline.py +++ b/timelapse_offline.py @@ -23,22 +23,41 @@ def main(): logging.info("Démarrage de la capture d'images en mode hors ligne") try: - # Chargement de la configuration + # Vérifier si une configuration active existe + is_active_config = config.get("config_active", False) + is_stopped = config.get("stop_current_config", False) remaining_images = config.get("nb_images_restantes", 0) - interval = config.get("timelapse", 3) # Intervalle par défaut: 3 secondes - logging.info(f"Configuration: {remaining_images} images à capturer, intervalle de {interval}s") - - if remaining_images <= 0: - logging.info("Aucune image à capturer en mode hors ligne") + # Si arrêté ou pas de configuration active, ne rien faire + if is_stopped: + logging.info("Configuration arrêtée, aucune action à effectuer") return - # Exécuter la séquence de capture en mode hors ligne - timelapse_manager.run_capture_sequence(online=False) + if not is_active_config: + logging.info("Aucune configuration active en mode hors ligne") + return + + if remaining_images <= 0: + logging.info("Aucune image restante à capturer") + # Désactiver la configuration puisqu'elle est terminée + config.update_config({"config_active": False}) + return - # Envoi de l'intervalle au microcontrôleur si nécessaire - if interval > 0: + logging.info(f"Configuration: {remaining_images} images à capturer") + + # Exécuter la séquence de capture en mode hors ligne + sequence_completed = timelapse_manager.run_capture_sequence(online=False) + + # Obtenir l'intervalle de timelapse pour le microcontrôleur si nécessaire + interval = config.get("timelapse", 3) + if interval > 0 and is_active_config and not sequence_completed: + logging.info(f"Envoi de l'intervalle au microcontrôleur: {interval}s") micro_controller.send_interval(interval) + else: + # Si la séquence est terminée, réinitialiser l'intervalle + if sequence_completed: + logging.info("Séquence terminée, réinitialisation de l'intervalle") + micro_controller.send_interval(0) # 0 pour désactiver except Exception as e: logging.error(f"Erreur lors de la capture en mode hors ligne: {e}") diff --git a/timelapse_online.py b/timelapse_online.py index 1acc66c..2aa6102 100644 --- a/timelapse_online.py +++ b/timelapse_online.py @@ -28,6 +28,14 @@ def main(): if status is None: logging.error("Impossible d'obtenir le statut de la caméra depuis l'API") + + # Dans le cas où une configuration active existe déjà, continuer avec celle-ci + if config.get("config_active", False) and config.get("nb_images_restantes", 0) > 0: + logging.info("Utilisation de la configuration locale existante") + timelapse_manager.run_capture_sequence(online=False) # Mode hors ligne si API inaccessible + else: + logging.info("Pas de configuration active, abandon de la capture") + sys.exit(1) # Mise à jour de la configuration @@ -42,10 +50,28 @@ def main(): if status.get("stop_flag", False): logging.info("Demande d'arrêt détectée, confirmation au serveur") api_client.confirm_stop() + + # Réinitialiser l'état actif + config.update_config({ + "config_active": False, + "nb_images_restantes": 0 + }) + + sys.exit(0) + + # Si le mode est IDLE et qu'aucune configuration n'est active, ne rien faire + if status.get("idle", True) and not config.get("config_active", False): + logging.info("Mode IDLE, aucune action à effectuer") sys.exit(0) # Exécuter la séquence de capture - timelapse_manager.run_capture_sequence(online=True) + sequence_completed = timelapse_manager.run_capture_sequence(online=True) + + # Si la séquence est terminée (toutes les images capturées), notifier l'API + if sequence_completed and config.get("nb_images_restantes", 0) <= 0: + logging.info("Toutes les images ont été capturées, notification au serveur") + # TODO: Implémenter une méthode pour notifier la fin de la séquence + # api_client.notify_sequence_complete() except Exception as e: logging.error(f"Erreur lors de la capture en mode connecté: {e}")