# Instructions après mise à jour ou rollback AppDaemon Préparé le 8 novembre 2026 pour cette installation `/conf`. À suivre par Codex après installation de **4.5.14**, ou retour en **4.5.10**. Ce document prépare l'intervention : sa rédaction n'a appliqué aucun patch ni redémarré le service. ## 1. Identifier l'installation avant toute modification Lire ce document et `docs/appdaemon-local-changes.md`. Conserver les modifications applicatives existantes, les configurations YAML et les exclusions de dossiers. Ne pas restaurer les anciennes instrumentations des utility loops : elles ont été retirées volontairement et archivées dans `tools/archive/`. Exécuter dans le conteneur, avec le Python réellement utilisé par AppDaemon : ```sh python3 - <<'PY' import inspect, sys from importlib.metadata import version import appdaemon from appdaemon.utils import deep_compare print('Python :', sys.executable) print('Version :', version('appdaemon')) print('Paquet :', appdaemon.__file__) print('deep_compare :', inspect.getsourcefile(deep_compare)) print(inspect.getsource(deep_compare)) PY ``` Si le processus utilise un autre environnement, employer son interpréteur pour les inspections, modifications et tests. Ne pas déduire la version du seul tag Docker. Vérifier aussi l'Entrypoint/Cmd du conteneur et le script effectivement exécuté ; une image personnalisée peut différer de l'image officielle. Pour une autre version que 4.5.10 ou 4.5.14, refaire la comparaison avec ses sources. Avant chaque édition, sauvegarder le fichier original dans un dossier daté sous `/conf/tools/backups/appdaemon--/`, en notant son chemin absolu, sa version et son empreinte SHA-256. Ne pas écraser une sauvegarde précédente. N'appliquer chaque changement qu'une fois ; si déjà présent, le vérifier. Ne jamais remplacer un fichier 4.5.14 par une sauvegarde 4.5.10. ## 2. Tableau des changements | Élément | 4.5.10 (rollback) | 4.5.14 | |---|---|---| | Timestamp de rafraîchissement HASS | Appliquer le patch `plugin.name` | Déjà intégré ; vérifier seulement | | Comparaison des clés dans `deep_compare` | Appliquer dans `utils.py` | Appliquer dans `utils/misc.py` | | Optimisation des logs ordinaires | Conserver le raccourci de `LoggerInterface` | Optimisation intégrée au core ; conserver le wrapper existant si compatible | | Archivage au démarrage Docker | Ajouter l'appel dans `dockerStart.sh` | Ajouter l'appel dans `/start.sh` pour l'image officielle | ## 3. Patch HASS : 4.5.10 seulement Dans le paquet installé, fichier `plugin_management.py`, méthode `update_plugin_state()`, remplacer uniquement cet appel dans le `finally` : ```diff - await self.refresh_update_time(plugin) + await self.refresh_update_time(plugin.name) ``` Cela évite de redemander l'état complet de Home Assistant chaque seconde après expiration du délai de rafraîchissement (10 minutes par défaut). Le correctif est intégré depuis 4.5.12 et confirmé dans le tag 4.5.14. En 4.5.14, contrôler la ligne, sans ajouter un second patch. Référence locale : `APPDAEMON_BANDWIDTH_BUG_FIX.md`. ## 4. Patch deep_compare : les deux versions Localiser le fichier avec `inspect.getsourcefile(deep_compare)` : - 4.5.10 : `appdaemon/utils.py`. - 4.5.14 : `appdaemon/utils/misc.py` (le module a été réorganisé). Dans `deep_compare()`, ajouter immédiatement après `data = data or {}` : ```python if check.keys() != data.keys(): return False ``` Conserver tout le reste de la fonction propre à la version installée. En particulier, garder `current = data.get(k)` en 4.5.14. Le début de fonction doit donc ressembler à ceci : ```python def deep_compare(check: dict, data: dict) -> bool: """Compares 2 nested dictionaries of values""" data = data or {} if check.keys() != data.keys(): return False # Suite existante, différente selon la version : ne pas la remplacer. ``` La 4.5.14 évite le KeyError à l'ajout d'une clé, mais ne détecte toujours pas certaines suppressions : la fonction officielle renvoie `True` pour `deep_compare({}, {'input_selection': {}})`. Le patch corrige aussi les suppressions imbriquées et distingue une clé absente d'une valeur `None`. Vérifier dans un nouveau processus Python après modification : ```sh python3 - <<'PY' from appdaemon.utils import deep_compare assert deep_compare({'input_selection': {}}, {}) is False assert deep_compare({}, {'input_selection': {}}) is False assert deep_compare({'x': {'a': 1}}, {'x': {}}) is False assert deep_compare({'x': {}}, {'x': {'a': 1}}) is False assert deep_compare({'x': None}, {}) is False assert deep_compare({'x': [1, 2]}, {'x': [1, 2]}) is True assert deep_compare({'x': [1, 2]}, {'x': [2, 1]}) is False assert deep_compare({'x': {'a': 1}}, {'x': {'a': 1}}) is True assert deep_compare({'x': {}}, {'x': None}) is False assert deep_compare({}, None) is True assert deep_compare({'input_selection': {}}, None) is False print('OK : 11 vérifications deep_compare') PY ``` Référence locale : `APPDAEMON_RELOAD_BUG_FIX.md`. Ses anciens chemins de sauvegarde `.bak` ne sont plus actifs ; utiliser la sauvegarde de cette intervention. ## 5. LoggerInterface : conserver les fonctionnalités locales Fichier persistant : `apps/ad_toolbox/logger_interface.py`, méthode `_write_log()`. En **4.5.10**, conserver le raccourci existant : pour un message texte sans `__module__`, `__line__` ou `__function__`, et avec les méthodes standard ADAPI, appeler `api._log()` sans passer par l'inspection de pile. Garder le repli vers `api.log()` pour les substitutions et les méthodes personnalisées. Préserver les options d'encodage, le routage des logs et les groupes de messages. Ne pas ajouter un autre patch dans `adapi.py` : il était volontairement revenu au code officiel 4.5.10. En **4.5.14**, `_sub_stack()` contient déjà le raccourci évitant `inspect.stack()` sans marqueurs. Aucun patch core de logging n'est nécessaire. Conserver le wrapper applicatif et ses fonctionnalités ; la suppression du raccourci local redondant est facultative, pas un prérequis de migration. Tester sa compatibilité. Tests existants : ```sh python3 -m unittest discover -s /conf/apps/ad_toolbox/unit_tests -p 'test_logger_interface_fast_path.py' -v python3 -m unittest discover -s /conf/apps/ad_toolbox/unit_tests -p 'test_logger_interface_grouping.py' -v ``` **Adaptation de test nécessaire en 4.5.14 :** `test_direct_log_is_not_modified` attend actuellement `stack.assert_called_once()` pour `api.log('Direct log')`. Cette attente correspond à 4.5.10. Pour 4.5.14, attendre `stack.assert_not_called()`. Si le test doit couvrir les deux versions, choisir explicitement l'attente selon la version installée, en conservant l'assertion d'identité de `_sub_stack`. Ne pas modifier le core pour satisfaire l'ancienne attente. Vérifier que les tests d'intégration ne sont pas ignorés faute d'import AppDaemon. ## 6. Patch dockerStart / start.sh : les deux versions ### Comportement local à préserver Avant le lancement d'AppDaemon, appeler une seule fois : ```sh sh "$CONF/archiveLogs.sh" ``` Ce script persistant archive les anciens `*.log*` et `memory_usage.csv` dans `/conf/logs/archive//`, puis lance le suivi mémoire en arrière-plan. Conserver le contenu actuel de `/conf/archiveLogs.sh`. Ne pas lancer le script manuellement pendant qu'AppDaemon écrit ses logs pour le « tester » : il déplacerait les fichiers ouverts. Ne pas lancer le script de démarrage complet dans le conteneur déjà actif : cela lancerait un second AppDaemon. ### 4.5.10 Le script observé est `/usr/src/app/dockerStart.sh`. `/conf/dockerStart.sh` est un **lien symbolique** vers ce fichier, pas une copie persistante du patch. Après recréation du conteneur, la cible peut être remplacée. Ajouter l'appel après les installations de dépendances, juste avant le lancement : ```sh sh "$CONF/archiveLogs.sh" # Lets run it! exec python3 -m appdaemon -c $CONF "$@" ``` ### 4.5.14 : changement de point d'entrée confirmé dans le tag officiel Le Dockerfile copie `scripts/start.sh` vers **`/start.sh`** et définit `ENTRYPOINT ["/start.sh"]`. Il n'utilise plus `dockerStart.sh`. Dans cette image, patcher `/start.sh`, pas l'ancien lien `/conf/dockerStart.sh`. Ajouter le même appel après l'installation des dépendances et avant l'exec : ```sh sh "$CONF/archiveLogs.sh" # Lets run it! exec uv run --frozen appdaemon -c $CONF "$@" ``` Conserver le lancement `uv`, les installations via `uv pip`, le `PYTHONPATH` et le répertoire de configuration exemple `/opt/conf` propres à cette version. Ne pas recopier l'ancien script 4.5.10 par-dessus `/start.sh`. Si l'image déployée possède un autre point d'entrée, transposer cet appel dans le script réellement utilisé et noter le chemin dans le compte rendu. L'ancien lien peut rester inutilisé ; ne pas le prendre comme preuve du patch. ### Vérification sans exécution ```sh sh -n /conf/archiveLogs.sh # Choisir le script réellement utilisé : sh -n /usr/src/app/dockerStart.sh # 4.5.10 # OU sh -n /start.sh # 4.5.14 officielle ``` Inspecter le script : exactement un appel actif à `archiveLogs.sh`, avant l'exec. Ces modifications hors `/conf` sont perdues lors d'une recréation du conteneur, comme les patchs Python. Les réappliquer à chaque nouvelle image, ou les intégrer explicitement à une image dérivée si cela fait partie de l'intervention demandée. ## 7. Redémarrage et validation finale Après application et vérifications, redémarrer le conteneur selon le mécanisme habituel de cette installation, dans le périmètre de l'intervention demandée. Un simple rechargement d'app ne remplace pas les fonctions core déjà importées et ne réexécute pas le script de démarrage. Vérifier après redémarrage : 1. Version réellement lancée et absence d'erreurs de démarrage/import. 2. Patch `deep_compare` toujours présent et 11 vérifications réussies dans le même environnement que le service (une installation de dépendances au boot pourrait avoir remplacé le paquet). 3. Message `[archiveLogs]`, archive créée si des anciens logs existaient, nouveau `memory_usage.csv`, un seul processus `archiveLogs.sh --watch-memory`. Vérifier l'ajout de mesures à l'intervalle configuré (300 secondes par défaut). Avec `uv`, le PID 1 peut être uv : si les colonnes RSS AppDaemon sont vides, vérifier le processus réel ; les métriques du conteneur restent distinctes. 4. Connexion Home Assistant et absence de rafraîchissements complets chaque seconde après le délai de refresh configuré (10 minutes par défaut). 5. Tests du logger réussis avec l'attente adaptée à la version. 6. Si un essai de reload réel est nécessaire, utiliser une app de test isolée sans action domotique ; vérifier ajout/suppression d'une clé imbriquée et nettoyer l'essai. Ne pas modifier chauffage/volets pour ce test. Mettre à jour `docs/appdaemon-local-changes.md` avec la version, les fichiers réellement modifiés, les sauvegardes, résultats et statut du redémarrage. Séparer les vérifications exécutées de celles restant à observer ; ne pas annoncer une validation du service sur la seule base des tests unitaires. ## 8. Rollback vers 4.5.10 Revenir à l'image 4.5.10 prévue par le déploiement, puis reprendre les sections 1 à 7 pour **4.5.10** : patch HASS + clés `deep_compare` + raccourci applicatif logger + appel d'archivage dans le vrai `dockerStart.sh`. Les fichiers `/conf` et le sous-module `apps/ad_toolbox` doivent être conservés. Si le test du logger a été rendu compatible avec les deux versions, le conserver. Ne pas restaurer de fichiers core 4.5.14 dans 4.5.10, ni les anciennes sondes de diagnostic archivées. Vérifier à nouveau après le redémarrage du rollback. ## Sources de référence - Inventaire : [appdaemon-local-changes.md](appdaemon-local-changes.md). - Diff core local 4.5.10 : [appdaemon-core-4.5.10.diff](appdaemon-core-4.5.10.diff). - [4.5.14 : plugin_management.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/plugin_management.py). - [4.5.14 : utils/misc.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/utils/misc.py). - [4.5.14 : adapi.py](https://github.com/AppDaemon/appdaemon/blob/4.5.14/appdaemon/adapi.py). - [4.5.14 : Dockerfile](https://github.com/AppDaemon/appdaemon/blob/4.5.14/Dockerfile). - [4.5.14 : scripts/start.sh](https://github.com/AppDaemon/appdaemon/blob/4.5.14/scripts/start.sh). - [4.5.10 : dockerStart.sh](https://github.com/AppDaemon/appdaemon/blob/4.5.10/dockerStart.sh).