Versatile Thermostat: Auto TPI Coefficients ( discussion math/algo )

EDIT: le projet a complètement changé, ce premier post n’a plus rien à voir avec la méthode employée dans l’auto TPI, je laisse qd même ça pour plus tard pour ne pas perdre les infos.

Salut

J’experimente l’intégration d’une fonction de configuration automatique des paramètres TPI de versatile thermostat.
Les fortiches en math sont les bienvenus, j’avoue que je suis à la limite de ce dont je me rappelle de mes cours de l’époque. :slight_smile:

**L’Auto TPI** (Time Proportional Integral) est une fonctionnalité intelligente qui apprend automatiquement et en continue les caractéristiques thermiques de votre pièce pour ajuster les coefficients TPI (`tpi_coef_int` et `tpi_coef_ext`) de manière optimale.

Au lieu de deviner des coefficients comme `Kp` (proportionnel) et `Ki` (intégral), le thermostat observe le comportement de votre pièce et calcule les meilleures valeurs pour vous.

Vous pouvez également utiliser ce service dans vos automatisations pour activer ou désactiver l’apprentissage dynamiquement.

## Principe de fonctionnement

L’Auto TPI observe le comportement de votre pièce (température intérieure, extérieure, puissance de chauffage) sur une période donnée pour construire un modèle thermique.

Il utilise un algorithme d’apprentissage basé sur la régression des moindres carrés pondérés pour identifier les paramètres physiques de la pièce.

Le moteur Auto TPI utilise des algorithmes avancés pour s’adapter en continu à votre environnement :

1. **Apprentissage intelligent** : Utilise un filtrage avancé (Savitzky-Golay) pour ignorer le bruit des capteurs et comprendre la véritable tendance de température.

2. **Réactivité Adaptative** : Ajuste automatiquement la vitesse de réaction du thermostat en fonction de l’isolation de votre pièce.

3. **Prise en compte de l’Humidité** : Si votre capteur d’humidité est disponible, l’algorithme prend en compte l’humidité.

4. **Auto-Nettoyage** : Il détecte les « mauvaises » données et les exclut de l’apprentissage.

5. **Détection de Dérive** : Si votre système de chauffage change (ex : changements saisonniers), il détecte le changement et peut mettre l’apprentissage en pause.

## Modèle Mathématique

Le modèle repose sur l’équation différentielle thermique suivante :

image

Où :

* dT_room / dt est la variation de température intérieure (dérivée).

* alpha est le coefficient de perte thermique (isolation).

* beta est l’efficacité du chauffage (puissance/volume).

* gamma est un terme de correction lié à l’inertie et à la boucle de contrôle.

* Power est la puissance de chauffage appliquée (0-100%).

### Algorithme de calcul

1. **Collecte de données** : Le système enregistre périodiquement les températures et la puissance.

2. **Filtrage** : Les données aberrantes sont écartées via une méthode IQR (Interquartile Range).

3. **Régression** : Une régression linéaire (moindres carrés pondérés) est effectuée pour trouver les valeurs optimales de alpha, beta et gamma qui minimisent l’erreur entre le modèle et la réalité. Les données récentes ont plus de poids (oubli progressif des anciennes données avec une demi-vie de 7 jours).

4. **Validation** : La qualité du modèle est évaluée via le coefficient de détermination R^2. Si R^2 < 0.3, le modèle est jugé insuffisant.

### Calcul des coefficients TPI

Une fois alpha et beta déterminés, les coefficients TPI sont calculés ainsi :

* **Coefficient Extérieur ($K_{ext}$)** :

K_ext = alpha/beta}

Il représente la puissance nécessaire (en %) pour compenser 1°C de différence avec l'extérieur.

Valeur bornée entre 0.01 et 0.20.

* **Coefficient Intérieur ($K_{int}$)** :

K_int = 1/(beta/tau_target)

Où tau_target est le temps de réponse souhaité (fixé à 30 minutes). Il représente la réactivité nécessaire pour corriger un écart de température intérieure.

Valeur bornée entre 0.01 et 1.0.

## Prérequis à l’apprentissage

Pour que l’apprentissage soit validé, il faut :

* Au moins 100 points de données.

* Au moins 10 cycles de chauffage complets détectés.

* Une qualité de modèle ($R^2$) suffisante (au moins « Fair » / > 0.3).

## Indicateurs de qualité & Suivi

L’état de l’apprentissage est visible via les attributs du thermostat :

* `learning_active` : `true` signifie qu’il collecte actuellement des données.

* `learning_quality` : Indique la confiance du système (`insufficient`, `poor`, `fair`, `good`, `excellent`).

* `confidence` : Pourcentage de confiance dans le modèle ($R^2 \times 100$).

* `time_constant` : Constante de temps thermique de la pièce (inertie).

### Interpréter les Attributs

* **Qualité** :

Insufficient: Pas encore assez de données. Continuez à utiliser le thermostat normalement.

Poor/Fair: Le modèle a quelques données mais les prédictions ne sont pas parfaites. Cela s'améliorera avec le temps.

Good/Excellent: Le système a une très bonne compréhension de votre pièce.

* **Constante de Temps ($\tau$)** :

Faible (< 2h) : Votre pièce chauffe et refroidit vite (faible inertie). Le thermostat sera plus agressif.

Élevée (> 10h) : Votre pièce a une forte masse thermique (ex : plancher chauffant, murs épais). Le thermostat sera plus lent et plus doux.

* **Confiance (R²)** : Un pourcentage montrant à quel point le modèle mathématique colle à la réalité. > 70% est excellent.

## Dépannage

* **L’apprentissage reste bloqué sur « Insufficient »** : Assurez-vous que vos capteurs de température sont fiables et mis à jour fréquemment. De grands trous dans les données peuvent ralentir l’apprentissage.

* **Le chauffage est erratique** : Si l’avertissement « Concept Drift » apparaît dans les logs, cela signifie que le comportement thermique a changé radicalement. Le système met généralement l’apprentissage en pause par sécurité. Vous pouvez envisager de réinitialiser l’apprentissage si vous avez fait des changements majeurs dans la pièce (ex : nouvelles fenêtres).

## Philosophie de l’algorithme (FAQ)

**Pourquoi ne pas utiliser les coefficients actuels pour calculer les nouveaux ?**

L’algorithme utilise une approche d’**Identification de Modèle Physique** et non une approche itérative (type « essai-erreur » ou « descente de gradient »).

1. **Indépendance de la Physique** : Les caractéristiques thermiques de votre pièce (isolation $\alpha$, puissance $\beta$) sont des constantes physiques. Elles ne dépendent pas des réglages du thermostat. Que votre thermostat soit mal réglé (oscillations) ou bien réglé, la relation physique `Puissance → Variation de Température` reste la même.

2. **Rapidité de convergence** : En identifiant directement la physique de la pièce, on peut calculer mathématiquement les coefficients « idéaux » en une seule fois (dès qu’on a assez de données). Une approche itérative qui essaierait d’ajuster petit à petit les coefficients prendrait des semaines (car chaque cycle de chauffage est lent) pour converger.

3. **Rôle des anciens coefficients** : Les anciens coefficients ont quand même un impact : ils déterminent la `Puissance` appliquée pendant l’apprentissage. Si les anciens coefficients sont « mauvais », ils vont provoquer des variations de température (oscillations). Paradoxalement, ces variations aident l’algorithme car elles « excitent » le système et permettent de mieux identifier ses réactions. Un système parfaitement stable est parfois plus difficile à identifier (moins de données dynamiques).

L’algorithme ne cherche donc pas à « corriger » les anciens coefficients, mais à « comprendre » la pièce pour proposer directement les bons réglages.

J’ai déjà commencé à intégrer ça et c ‘est en test depuis hier.

Je n’en suis encore qu’à la phase d’accumulation de donnée, donc pour l’instant aucune idée si cela va fonctionner correctement ^^

Maintenant tout ça est très théorique, et j’aurais souhaité connaitre vos avis concernant l’approche.

8 « J'aime »

J’ai essayé.
J’ai un fichier “fourre tout” qui expérimente plusieurs méthodes.
Pour l’instant les résultats sont concluent pour moi sur la recherche de coef_int et de coef_ext optimaux.

Sinon, j’ai aussi un fichier pour déterminer les paramètres 1r1c d’une pièce si tu aime faire de la modélisation.

1 « J'aime »

Ah oui ça m’intéresse clairement. En fait c’est en tombant sur cette formule plus ou moins par hasard que je me suis lancé dans le test.

J’ai aussi regardé comment faisait Jeedom, c’est de l’iteratif. J’aimerais éviter si possible.

Si possible, envoie moi ton adresse mail en MP, je t’envoie les deux fichiers.

top bien reçu merci. T’es plus calé que moi sur le sujet je vois.

Avant de pomper tes algos si j’échoue, je me permet de te piquer déjà quelques idées que j’aime beaucoup:

  • Évaluer la qualité du modèle sur des données futures (pas vues pendant l’apprentissage).
  • Combiner plusieurs algorithmes et faire un vote pondéré
  • j’avais pas pensé à ignorer les données de l’hysteresis
  • j’aime bien ton isolation forest. J’ai déjà_is_outlier() (IQR), mais ta méthode est plus robuste

Pas de problème !
Si mes vieux cours d’automatisme peuvent servir… :blush:

En automatisme, théoriquement, il faut suivre plusieurs étapes pour identifier un modèle ou optimiser des paramètres de régulation :

  1. Acquisition des données brutes (via API, capteurs, etc.).
  2. Nettoyage des données (filtrage, normalisation, gestion des NaN).
  3. Validation des données (vérification de la cohérence, détection d’outliers, stabilité).
  4. Recherche et optimisation (identification des paramètres via grid search, optimisation locale, ou méthodes bayésiennes/ML).
  5. Validation de la solution (cross-validation, métriques comme MSE/RMSE, tests sur données réelles).
  6. Déploiement/export (envoi des paramètres optimisés, visualisation).

C’est exactement ce que j’ai essayé de faire dans mon code, en m’inspirant de ces principes pour calibrer le thermostat. :

  1. load_thermostat_history, _load_from_api, _load_from_db : acquisition via API HA ou DB SQLite.
  2. _normalize_api_db, prepare_dataset (filtre hvac_action, window/safety states, clip températures, etc.), et gestion des NaN/outliers via Isolation Forest.
  3. validate_data (checks stricts sur bornes, NaN, etc.), check_data_quality (variance minimale, stabilité).
  4. train_validate_best (ensemble d’optimiseurs : Grid, Nelder-Mead, Bayesian), predict_coef_xgb (XGBoost comme surrogate), et refine_valley_minimum (raffinement local).
  5. Backtest avec MSE/RMSE/accuracy/overshoot dans train_validate_best, cross-validation temporelle, et plots comme loss_landscape_ci_ce.png pour visualiser la surface de perte.
  6. Exports JSON/CSV, plots via make_plots et plot_results.

La minimisation de la perte est centrale : compute_loss_for_pair, score_loss (MSE + pénalité overshoot), et le graphique montre bien la « vallée » des optima.

Concernant le chauffage dans le cas du VTH, tu as une fonction paramétrique avec deux entrées : coef_int (lié à l’inertie intérieure) et coef_ext (lié aux pertes extérieures). Il ne faut pas optimiser ces deux coefficients indépendamment, mais trouver la meilleure paire qui minimise globalement la perte (loss), pour améliorer le confort thermique (moins d’overshoot, meilleure stabilité).

Mon code fait précisément ça : il minimise une fonction de perte (basée sur MSE + pénalités), comme tu peux le voir sur le graphique loss_landscape_ci_ce qui montre la surface de perte en fonction des paires (ci, ce). J’utilise un ensemble d’optimiseurs (grid, Nelder-Mead, Bayesian) et même XGBoost comme surrogate pour raffiner, avec une validation croisée pour éviter le sur-apprentissage. Mais, je vais abandonner XGBoost, je ne le maitrise pas correctement.

Apres, ton approche est différente, si j’ai bien compris :

  1. Il tourne en live dans Home Assistant.
  2. Il accumule les points en temps réel pendant les cycles de chauffe
  3. À chaque cycle (ou toutes les X minutes), il calcule l’écart entre le on_percent réel et le on_percent théorique
  4. Il ajuste très progressivement coef_int et coef_ext via une petite règle de type descente de gradient (learning_rate adaptatif)
  5. Il clip, il surveille la stabilité, et il pousse automatiquement les nouveaux coefs dans le thermostat

Mon script, lui, est plutôt fait pour un calibrage offline sur plusieurs jours d’historique, avec des méthodes plus lourdes mais plus précises (ensemble + ML). Ce n’est pas le même usage.

En fait, moi pour l’instant, je le fais tourner une fois par semaine et j’adapte les coef. Pour l’instant les ajustements sont minime, voir inexistant.
De plus ils sont cohérents avec mes pièces de la maison.

Si besoin, n’hésite pas à me demander.

1 « J'aime »

Merci pour ces “eclaircissements”. Je digère ça.

Apres, ton approche est différente, si j’ai bien compris :

Oui, l’idée c’est qu’il tourne constamment en live, et ajuste dynamiquement les paramètres au cours des saisons. Sachant que je n’utilise pas les mêmes coeff quand il fait vraiment très froid que tempéré. ( défaut d’isolation probablement )

J’ai ajouté un simulateur hier avec un jeu de données fictif, pour l’instant ça à l’air de se tenir.
Par contre j’ai un soucis sur la capture de données, il faut que je vérifie car j’ai des thermostats qui choppent très peu de données contrairement à d’autre et je n’ai pas encore trouvé pourquoi.
Les données sont filtrées en entrée, j’ai surement un soucis de ce coté là. J’ai ajouté hier le filtrage des data pendant les phases d’hysteresis, et comme il fait pas très froid en ce moment, il doit souvent rester dans cette zone.

Oui, je teste la variance des datas. Si elle est faible, normalement le script prévient.

Bon courage pour ton script.

J’ai voulu tester ton script mais il me vire toutes mes données. En meme temps j’ai plus que 5 jours d’historique, le passage a versatile v8 ( ou un des nombreux tests que j’ai pu faire ) m’a effacé mon historique

─────── Calibration TPI • single ─────────

[2025-11-25 15:34:08] INFO Features: SCIPY=True | JOBLIB=True | BAYES=True | NUMBA=True | n_jobs=4
[11/25/25 15:34:08] WARNING [VTherm] resolve_tpi_runtime_params a échoué (‹ BASE_URL ›) → fallback CLI.
INFO Paramètres: thermo=climate.thermostat_salon | jours=5 | cycle=10 min
INFO Timezone: Europe/Paris
INFO Bornes ci: [0.1,10.0] pas 0.01
INFO Bornes ce: [0.01,1.0] pas 0.001
INFO Seuils TPI: high=1.5°C | low=0.2°C
INFO Délais min: on=45 s | off=45 s
INFO [WGT] Demi-vie pondération: 4.0 jours
──────── Chargement des données ─────────

INFO Lecture API (via .env) | thermostat=climate.thermostat_salon
[2025-11-25 15:34:14] INFO climate.thermostat_salon: variabilité on%=nan, temp_int=0.407
INFO Préparation du dataset…
[11/25/25 15:34:14] INFO Nettoyage: 7200 → 0 lignes apres dropna
INFO Interpolation lineaire appliquee sur [‹ consigne ›, ‹ temp_int ›, ‹ temp_ext ›, ‹ on_percent ›]
INFO Garde hvac_action in [‹ heating ›,‹ idle ›]: 0 lignes
INFO Filtre window_state!=off: 0 → 0 lignes
INFO Filtre safety_state!=off: 0 → 0 lignes
INFO Filtre overpowering_state!=off: 0 → 0 lignes
INFO Cible y non-NaN: 0 lignes
Dataset préparé vide — arrêt.

Nettoyage: 7200 → 0 lignes apres dropna
C’est plutot cela qui est bizarre, il drop l’ensemble des datas.
Si tu le souhaites, je peux d’envoyer un .env, je te fais un token le temps que tu testes chez toi.

Concernant ton script :
Je ne suis pas certain qu’il soit pertinent de modifier les coefficients à chaque cycle. L’évolution thermique d’une pièce est lente, et on considère généralement qu’il faut environ cinq constantes de temps (5 × tau) pour atteindre un état stable.

1 « J'aime »

Je viens de voir qu’il manque une ligne dans le code que je t’ai envoyé :

@classmethodclassmethod
def from_home_assistant(
cls,
entity_id: str = « climate.thermostat_cuisine »,
) → VThermostatState | None:
«  »"
Récupère l’état du VTherm via l’API REST de Home Assistant (/api/states).


    Parameters
    ----------
    entity_id : str
        Identifiant de l'entité (ex: 'climate.thermostat_cuisine').

    Returns
    -------
    VThermostatState | None
        Instance typée si succès, None en cas d'erreur réseau/HTTP.
    """
    load_dotenv(".env") #   < ------------------ a rajouter
    base_url = os.environ["BASE_URL"].rstrip("/")
    token = os.environ["TOKEN"]

Mais ce n’est pas cela qui drop les valeurs.

il utilise 5 cycles de chauffage et attend ‘avoir un modèle jugé “good” avant de calculer les K, plutôt au moins 10-15 cycles.
Pour l’instant une fois qu’il a accumulé son total de données, il calcule à chaque cycle, mais je dois changer ça pour qu’il récupère n cycles avant de recalculer.

dans calibrate_v2.py j’ai bien déjà le chargement du .env:

def _load_from_api(
entity: str,
days: int = 14,
tz: str = « Europe/Paris »,
resample: str = « 1min »,
base_url: str | None = None,
token: str | None = None,
) → pd.DataFrame:
«  »« Charge les donnees depuis l’API Home Assistant. »«  »

load_dotenv(".env")  # charge .env une fois

base_url = base_url or os.getenv("BASE_URL")
token = token or os.getenv("TOKEN")


non, c’est dans le lignes environs 930.
dans la class VThermostatAttributes(BaseModel):

@classmethod
def from_home_assistant(
cls,
entity_id: str = « climate.thermostat_cuisine »,
) → VThermostatState | None:

mais c’est pas ça qui bloque normalement l’import des datas, je vais chercher.

Edit : Je ne comprend pas pourquoi, en dessous de 7 jours il drop l’ensemble des datas… Je vais chercher…

Edit 2 : J’ai trouvé. Avec la mise à jour de vth, les Attributs on changé de place. Je fais la mise à jour du script et je te le renvoie par mail.

2 « J'aime »

Ah top ca, je testerais ça. De mon coté, ca commence à me sortir quelques resultats corrects, mais ça manque encore de données:

Mais ça depend des pièces.
Je me rends compte que la modélisation thermique d’une pièce exige beaucoup de paramètres pour contenter tous les cas de figures. Pour une pièce correctement isolé, l’algo que j’ai fais tiens bien, par contre pour les autres il faudrait y ajouter la météo, le rayonnement solaire, l’orientation des murs, les fenètres, etc. Ca deviendrait une usine à gaz.
Et le temps d’attente pour avoir suffisement de données devient plus long qu’une méthode itérative, c’était pas le but.

Du coup je me suis repenché sur l’approche itérative de Jeedom qui a fait ses preuves. J’attend qd meme d’accumuler plus de data avant de changer d’approche.

Je vais aussi étudier ta méthode, dommage que j’ai perdu toute mon historique vtherm.

J’ai une question pour @Jean-Marc_Collin . Je n’ai pas de système de clim reversible ici, mais la régulation dans les 2 sens ( chaud / froid ) ne necessiterait pas des coeefficients differents pour chauffer et refroidir ?

Dans les simulations que j’ai pu faire, j’obtiens des coeffs bien differents pour les 2 modes et du coup je ne sais pas trop comment faire pour pas que ca écrase les coeff hiver quand on arrive en été.
A part peut être créer une banque de coeff TPI classées par condition climatiques, et faire switcher les coeff automatiquement vers le modèle qui se rapproche le plus des conditions actuelles.

Je vois que la régulation jeedom utilise 2 paires de coeff Int/ext, une pour chaque mode.
Je suis curieux d’avoir ton avis

Oui le modèle 1r1c à ces limites, et le 2r2c devient plus compliqué à paramétrer.

Je t’ai renvoyé par mail la mise à jour du script.

Maintenant, je vais travailler sur le modèle 1r1c sans capteur de puissance réel.
Chez moi, j’ai des modules nodon, donc j’ai la valeur réelle de puissance.
Pour l’instant, je fallback avec le mean_power_cycle du vth, mais cela donne des résultats incohérents.

J’ai pas encore regardé tes modeles 1r1c 2r2c. J’insiste encore sur le modele initial que j’ai complété en tete du topic

Je ne retrouve plus le message, mais je rebondi sur ta remarque sur la constante de temps car peut être que je fais fausse route.
Dans mes calculs la constante de temps est celle de la pièce pas du radiateur.
C’est une valeur théorique qui lie la vitesse de changement à la différence de température avec l’extérieur.
La formule approximative est Constante de temps≈ Difference Temperature (Interieur - Exterieur)​/Vitesse de changement (°C/h)

pour vulgariser, supposons qu’il fasse 10°C dehors et 20°C dedans.

  • L’écart est de 10°C.

  • on observe une perte de 1°C par heure quand c’est éteint.

Constante de temps = 10°C / 1°C de l’h

Pour moi, non. Tu fais plutôt référence à la vitesse à laquelle la température intérieure évolue en fonction de l’écart intérieur / extérieur.
En thermique, on modélise ça avec une constante de temps tau, qui vaut R fois C (résistance thermique * capacité thermique).

Tau représente le temps nécessaire pour atteindre environ 63 % de la variation finale après un changement. La stabilité est atteinte vers 5 fois tau.
Concrètement, avec un chauffage allumé à puissance constante, la pièce ne chauffe pas instantanément : elle monte progressivement, un peu comme une casserole d’eau sur une plaque. Plus l’inertie est grande, plus ça monte lentement.
Exemple : si tau = 7 h, alors après 7 h on a atteint ~63 % de la température finale, et la stabilité est atteinte vers 35 h (5 × 7 h). En fait, j’ai refais rapidement un essai chez moi, 7h est réaliste.

On peut alors écrire que le coefficient k vaut 1 / tau, et que plus tau est grand, plus la pièce réagit lentement aux changements de température.

Cependant, tu as raison sur un point : la constante de temps est bien celle de la pièce, pas du radiateur, car elle dépend de l’inertie thermique et de l’isolation.
En revanche, ta formule “Delta T / vitesse de changement” n’est qu’une estimation ponctuelle, pas une définition physique de la constante de temps.

Le modèle thermique standard du premier ordre s’écrit :

dTint/dt = - (1 / tau) * (Tint - Text)
k = 1 / tau
dTint/dt = - k * (Tint - Text)

et :

tau = R * C

avec :
R = résistance thermique (K/W)
C = capacité thermique (J/K)

1 « J'aime »

Excellent ! Je vais suivre de près cette superbe réalisation. J’adore l’approche et j’ai hate de voir ce que cela va donner. J’avoue que le réglage des coef du TPI est une source intarissable d’anos et de questions. Si je peux aider, en quoique ce soit tu n’hésites pas (je suis grave à la bourre mais ca m’intéresse bien). Y a un autre projet qui permet de prévoir les changements de preset à l’avance pour que la pièce soit à température à l’heure dite. Ca utilise aussi des modèles prédictifs. Je me demande si il n’y a pas du rapprochement à faire.

Dans l’idée à termes si ca fonctionne, tu vois ça directement dans VTherm ou comme une extension autonome ? Je peux fournir un service de mise à jour des coef qui peut être appelé depuis l’extérieur sans trop de soucis.

2 « J'aime »