12 KiB
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 :
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-<version>-<date>/, 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 :
- 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 {} :
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 :
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 :
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 :
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 "$CONF/archiveLogs.sh"
Ce script persistant archive les anciens *.log* et memory_usage.csv dans
/conf/logs/archive/<horodatage>/, 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 "$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 "$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 -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 :
- Version réellement lancée et absence d'erreurs de démarrage/import.
- Patch
deep_comparetoujours 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). - Message
[archiveLogs], archive créée si des anciens logs existaient, nouveaumemory_usage.csv, un seul processusarchiveLogs.sh --watch-memory. Vérifier l'ajout de mesures à l'intervalle configuré (300 secondes par défaut). Avecuv, 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. - Connexion Home Assistant et absence de rafraîchissements complets chaque seconde après le délai de refresh configuré (10 minutes par défaut).
- Tests du logger réussis avec l'attente adaptée à la version.
- 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.
- Diff core local 4.5.10 : appdaemon-core-4.5.10.diff.
- 4.5.14 : plugin_management.py.
- 4.5.14 : utils/misc.py.
- 4.5.14 : adapi.py.
- 4.5.14 : Dockerfile.
- 4.5.14 : scripts/start.sh.
- 4.5.10 : dockerStart.sh.