Nuit, oxygène et mesures
L'oxygène et le sommeil de la nuit, les mesures du quotidien et la zone habituelle de chaque valeur.
Chaque algorithme est décrit avec ce qu’il lit, ses étapes, les valeurs qu’il utilise (avec leur emplacement dans le code), ce qu’il affiche et ses limites.
Biais des capteurs et des algorithmes : ce que Trévor dit et les mesures proposées
Trévor explique que les oxymètres, les montres, les bagues et les caméras de téléphone peuvent afficher un oxygène plus haut que la réalité sur une peau foncée, et que ses propres calculs héritent de ce biais. Il propose cinq mesures pratiques. Ce texte est affiché et n'est pas un calcul.
Où tu le vois : Bot : bouton « ⚖️ Biais des capteurs, mesures possibles » de « Mon oxygène » et fin de l'écran « Ma nuit » ; application (GET /api/phone/nuit).
Ce que l’algorithme lit
- Aucune donnée personnelle : même texte pour tout le monde (textes fixes)
Le calcul, étape par étape
Ce qui est affiché
Trois messages fixes (« Biais des capteurs », « Biais des algorithmes », « Mesures possibles ») montrés avec le rappel sur la nuit. Aucune valeur n'est corrigée en fonction de la couleur de peau : Trévor n'applique aucune correction numérique du biais, ni pour la montre ni pour la caméra.
Ce que cet algorithme ne sait pas faire
- Le texte ne mesure pas le biais de ton appareil : il ne peut pas dire de combien il se trompe pour toi.
- Le calibrage personnel de la caméra suppose que ton oxymètre de référence est juste.
- Les alertes d'oxygène restent à 92 % et 88 % pour tout le monde, sans ajustement selon la peau.
- Le texte cite Sjoding et coll. (NEJM 2020) et la FDA (2021) ; le dépôt note que les chiffres de Sjoding n'ont pas été relus et que la date exacte de la communication FDA de 2021 n'est pas vérifiée.
- Le texte dit que l'oxymètre frontal serait moins sensible à la couleur de peau selon certaines études, sans les citer.
Code : data/i18n/fr.json (textBiasWhy, textBiasAlgo, textBiasMeasures, textBiasBtn, textNightDisclaimer), src/trevor/conversation/night_screen.py (blocks), src/trevor/conversation/spo2_screens.py (on_spo2), src/trevor/media/ppg_spo2.py (docstring)
Météo et qualité de l'air de ton lieu de vie
Trévor récupère chaque jour la météo et la qualité de l'air de l'endroit où tu vis et en garde un résumé journalier, pour le mettre en regard de la façon dont tu vas. Il n'invente rien : sans position ou sans réponse du service, la série reste vide.
Où tu le vois : Courbes d'environnement du tableau de bord de la vie, bilan des quinze jours de moments, contexte du jour.
Ce que l’algorithme lit
- Position du domicile (arrondie à environ 1 km) (profil)
- Réponses d'Open-Meteo et d'Open-Meteo Air Quality (CAMS) (services externes sur Internet)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
MAX_PAST_DAYS | 92 | Plafond d'Open-Meteo pour les jours passés | src/trevor/navigator/environment.py:23 |
BACKFILL_DAYS | 60 | Historique demandé à l'activation | src/trevor/navigator/environment.py:24 |
place_key | 2 décimales | Lieu arrondi à environ 1 km | src/trevor/navigator/environment.py:54 |
timeout | 10 s | Délai de chaque appel | src/trevor/navigator/environment.py:127 |
unités | °C ; % ; hPa ; km/h ; mm ; µg/m³ ; grains/m³ ; m | Unités des variables | src/trevor/navigator/environment.py:28-48 |
niveau de preuve | modéré, faible, aucune | Niveau de preuve noté pour chaque variable d'après la recherche du 7 octobre 2026 (température min et max, baisse de température, température ressentie, vent, PM2,5 : modéré ; UV, poussières, pollens : aucune) | src/trevor/navigator/environment.py:27-48 |
Ce qui est affiché
Une table jour par jour des variables, avec l'attribution « Open-Meteo, CAMS (Copernicus) ». Rien ne dit que ces variables causent une crise.
Un exemple chiffré
Calcul exécuté avec le code : le 4 novembre, maximum 12,0 °C, minimum 4,0 °C, pression 1015,0 hPa ; le 5 novembre, maximum 7,5 °C, minimum 1,0 °C, pression 1008,2 hPa. Pour le 5 novembre : baisse de température 4,5 °C, variation de pression -6,8 hPa, écart dans la journée 6,5 °C.
Ce que cet algorithme ne sait pas faire
- La météo est celle du point de ton domicile, pas de l'endroit où tu es allé ce jour-là.
- Les valeurs passées viennent d'une prévision rafraîchie : ce sont des estimations de modèle et non des mesures de station.
- Les pollens sont des valeurs modélisées, expérimentales, avec environ 2022 comme début d'historique.
- L'usage gratuit d'Open-Meteo est réservé au non commercial : le code note que c'est à confirmer pour ce produit.
- Aucune explication causale.
Code : src/trevor/navigator/environment.py (fetch_days, parse_forecast, parse_air, record, location_of)
Mesures du jour de la montre : pas, pouls, HRV, température, stress, et signaux repérés
Trévor range chaque jour les mesures de ta montre ou de ta bague (une valeur par jour), écarte les valeurs impossibles, complète l'écart de température quand l'appareil donne seulement la température, puis compare tes 7 derniers jours aux 30 jours d'avant. Il liste aussi des signaux factuels (oxygène bas, pouls élevé, HRV basse, température, respiration, nuits courtes). Ce n'est pas un dispositif médical validé.
Où tu le vois : Récapitulatif « Tes mesures : moyenne des 7 derniers jours » et « Signaux repérés » du bot, courbes du journal, suivi du jour, écran « Ma santé » de la montre, phrases de coaching sans chiffre.
Ce que l’algorithme lit
- Pas, pouls au repos et moyen, HRV, sommeil, oxygène, fréquence respiratoire, température cutanée, stress, bruit ambiant, calories, distance, minutes actives (Oura, Fitbit, Open Wearables, exports Samsung, Apple, Google Fit, Garmin, webhook de l'application, oxymètre saisi)
- Indicateur « journée en cours » (partial) (webhook : jour d'aujourd'hui ou plus tard)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
SUMMARY_KEYS | steps, sleep_minutes, resting_hr, hrv, spo2, readiness, temp_deviation, skin_temp, respiratory_rate, noise_db | Mesures résumées | src/trevor/wearables/service.py:49 |
NIGHT_KEYS | night, sleep_minutes, hrv, skin_temp, temp_deviation | Mesures de la nuit gardées dans une journée partielle | src/trevor/wearables/service.py:48 |
seuil de différence | 5 % | Différence affichée si elle atteint 5 % de la référence | src/trevor/wearables/service.py:399 |
TEMP_BASELINE_DAYS | 30 | Fenêtre de la médiane de la température | src/trevor/wearables/models.py:112 |
TEMP_BASELINE_MIN | 3 | Nuits minimales pour un écart de température | src/trevor/wearables/models.py:113 |
signal pouls | +10 bpm | Pouls au repos vs médiane des 30 jours d'avant (5 jours minimum) | src/trevor/wearables/service.py:488 |
signal HRV | 0,75 x référence | HRV d'au moins 25 % sous la médiane | src/trevor/wearables/service.py:490 |
signal température | 0,5 °C | Écart de température cutanée | src/trevor/wearables/service.py:492 |
signal respiration | 20 /min | Fréquence respiratoire | src/trevor/wearables/service.py:494 |
signal sommeil | 300 min, 3 nuits, 120 min minimum | Moins de 5 h trois nuits de suite ; sous 2 h la nuit ne compte pas | src/trevor/wearables/service.py:497-505 |
bruit ambiant | dB(A) | Exposition sonore lue par la montre ; aucun son n'est gardé | src/trevor/wearables/models.py:31 |
stress_score | /100 | Score de stress de la montre (moyenne du jour pour Samsung) ; non repris dans le récapitulatif, lu par le modèle de risque | src/trevor/wearables/files.py:314 |
Ce qui est affiché
Pour chaque mesure : valeur moyenne des 7 derniers jours, écart avec les 30 jours précédents si assez grand, et, si l'interprétation est activée, une liste de signaux factuels avec la date. Exemple de ligne : « Fréquence cardiaque au repos : 58 bpm (+6 vs 30 jours précédents) ». Les signaux sont présentés comme des faits à discuter avec ton équipe soignante.
Un exemple chiffré
Calcul exécuté avec le code, au 6 novembre 2026 : 24 jours à 60 bpm de pouls au repos, puis le 30 octobre 71 bpm et un oxygène de 91 %. Résultat : deux signaux le 30 octobre, « SpO2 nocturne 91 % » et « FC repos 71 bpm (référence 60) ». Autre exemple : 7 nuits de température cutanée alternant 33,1 et 32,9, puis 34,0 : écart calculé +0,9 °C (médiane des nuits d'avant : 33,1).
Ce que cet algorithme ne sait pas faire
- Une seule valeur par jour : un pic de pouls ou une baisse d'oxygène de quelques minutes n'apparaît pas dans ce résumé.
- La priorité d'une source sur l'autre dépend seulement de l'ordre (Oura et Fitbit en dernier) et non de la qualité réelle des mesures.
- Quand deux sources donnent des valeurs différentes le même jour, l'une efface l'autre sans que tu le voies.
- Le score de stress est stocké mais n'apparaît pas dans le récapitulatif ; la fréquence cardiaque moyenne et le maximum non plus.
- Sans interprétation activée, la liste des signaux reste vide.
- Aucune déduplication des sessions de sommeil n'est faite par Trévor : pour Samsung, les sessions d'un même jour s'additionnent ; pour Oura, seul le type « long_sleep » est lu ; pour Fitbit, la session principale (isMainSleep) fournit le détail.
- Les mesures de la montre dépendent du capteur et sont moins fiables au mouvement et sur peau foncée.
Code : src/trevor/wearables/service.py (_day_rows, series, summary, summary_text, qualitative_summary, grounded_values, signals, handle_webhook), src/trevor/wearables/models.py (clean_day, derive_temp_deviation, merge_days), src/trevor/storage/database.py (upsert_wearable_days, wearable_days), src/trevor/wearables/files.py, src/trevor/wearables/day_view.py
Quinze jours de « moments » : bilan de tes moments difficiles et de l'environnement
Si tu l'actives, Trévor te demande deux fois par jour pendant quinze jours comment tu te sens là, maintenant (bien, moyen, pas bien). À la fin, il compare les jours difficiles aux autres jours sur l'environnement et écrit au plus deux conditions qui diffèrent, sans parler de cause.
Où tu le vois : Questions du bot à 10 h–11 h et 16 h–17 h ; bilan envoyé le lendemain de la fin de la période.
Ce que l’algorithme lit
- Réponses « bien », « moyen », « pas bien » (une par créneau) (déclaration)
- Environnement du jour (voir météo et air) (Open-Meteo, CAMS)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
BURST_DAYS | 14 | Durée de la période (aujourd'hui + 14 jours = 15 jours) | src/trevor/navigator/ema.py:20 |
SLOT_HOURS | am 10-11, pm 16-17 | Heures de Genève où un créneau peut partir | src/trevor/navigator/ema.py:21 |
MAX_LOG | 120 | Réponses gardées | src/trevor/navigator/ema.py:22 |
MIN_DAYS_PER_GROUP | 3 | Jours minimaux par groupe | src/trevor/navigator/ema.py:23 |
MIN_EFFECT | 0.5 | Écart standardisé minimal (d de Cohen) | src/trevor/navigator/ema.py:24 |
MAX_CONDITIONS | 2 | Conditions citées au plus | src/trevor/navigator/ema.py:25 |
SCORE | good 2, mid 1, bad 0 | Valeur des réponses | src/trevor/navigator/ema.py:26 |
écart de créneau | 0.25 | Différence de part de « pas bien » pour citer un créneau | src/trevor/navigator/ema.py:122 |
Ce qui est affiché
« Sur N moments : X bien, Y moyen, Z pas bien », éventuellement le créneau le plus difficile, et au plus deux phrases du type « Les jours moins faciles, [condition] : moyenne A contre B ». Une dernière phrase rappelle que ces chiffres sont des repères sur quinze jours et n'indiquent jamais une cause. Les réponses ne servent pas aux alertes de crise.
Un exemple chiffré
Calcul exécuté avec le code : sur trois jours difficiles où la température maximale vaut 2, 4 et 3 °C et trois autres jours où elle vaut 8, 9 et 10 °C, l'écart standardisé est -1,93 ; sa valeur absolue dépasse 0,5, donc cette variable est retenue (moyenne 3,0 contre 9,0).
Ce que cet algorithme ne sait pas faire
- Avec 3 jours de chaque sorte et vingt variables testées, des écarts apparaissent par hasard : le bilan ne corrige pas les comparaisons multiples.
- Seule la valeur absolue de l'écart sert à classer ; le sens est donné par les deux moyennes.
- Un jour avec une seule réponse compte autant qu'un jour avec deux.
- Il n'y a aucune cause établie : la corrélation sur quinze jours n'est pas une preuve.
- Les variables d'environnement viennent du lieu de ton domicile.
Code : src/trevor/navigator/ema.py (due_slot, answer, summary, _group_stats, summary_lines), src/trevor/navigator/environment.py (VARIABLES)
Ma nuit : ta normale, nuits plus basses, durées sous 90 % et alertes
Trévor compare l'oxygène moyen de chaque nuit à ta propre normale des 30 nuits précédentes et marque les nuits nettement plus basses. Il signale aussi les durées sous 90 %, une série de nuits basses et un oxygène très bas mesuré, et c'est alors la sécurité qui passe avant tout. Ce n'est pas un diagnostic.
Où tu le vois : Écran « Ma nuit » du bot et GET /api/phone/nuit ; alerte douce facultative (éteinte par défaut) envoyée au plus une fois par jour.
Ce que l’algorithme lit
- Nuits des 14 derniers jours et des 31 jours avant (oxygène, sommeil, source) (montre, bague, saisie à la main)
- Réponse « As-tu bien dormi ? » et sueurs de la nuit (0, 1, 2) (déclaration dans le suivi du jour)
- Dernière valeur d'un oxymètre au doigt saisie hier ou aujourd'hui (déclaration (source « oximeter »))
- Seuils d'urgence 88 % et 3 nuits (data/emergency_thresholds.json)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
NIGHT_TOO_FEW | 7 | Nuits mesurées nécessaires pour parler de « ta normale » | src/trevor/wearables/service.py:1068 |
NIGHT_DROP_Z | -1.5 (crisis.DROP_Z) | Une nuit est « en baisse » à 1,5 écart ou plus sous la normale | src/trevor/wearables/crisis.py:189 |
BASELINE_DAYS | 30 | Nuits antérieures de la normale | src/trevor/wearables/crisis.py:121 |
MIN_SD oxy_mean | 0.7 | Écart minimal de la normale d'oxygène (points) | src/trevor/wearables/crisis.py:166 |
night_spo2_very_low | 88 % | Oxygène très bas : urgence (« à valider par les HUG ») | data/emergency_thresholds.json:11 |
night_spo2_repeated | 3 nuits | Nuits basses de suite avant la phrase de répétition | data/emergency_thresholds.json:12 |
sweat n_both | 10 | Nuits minimales pour la phrase sur les sueurs | src/trevor/wearables/service.py:1136 |
fenêtre sueurs | 90 jours | Période de l'association entre sueurs et nuits basses | src/trevor/wearables/service.py:1155 |
jours affichés | 14 | Nuits montrées à l'écran | src/trevor/conversation/night_screen.py:102 |
Ce qui est affiché
Un écran en deux messages : sécurité d'abord (urgence ou rappel), ta normale (« oxygène moyen X %, sur N nuits »), une ligne par nuit (date, oxygène moyen, sommeil, drapeaux ⚠️ 🔄 👍 👎 💦), puis les nuits plus basses, les durées sous 90 %, l'avertissement sur la qualité, la divergence montre et réponse, les sueurs, la série de nuits basses, l'avertissement sur les capteurs et les conseils généraux. Le seuil bas de ta normale s'affiche en interne (low_cut = médiane - 1,5 x écart) sans apparaître dans le texte.
Un exemple chiffré
Calcul exécuté avec le code : 8 nuits à 95, 95,5, 96, 95, 96,5, 95,5, 95 et 96 % donnent une médiane de 95,5 et un écart de 0,74. Une nuit à 94,0 % a z = (94 - 95,5) / 0,74 = -2,0, donc elle est marquée plus basse (seuil bas à 94,4 %). Une nuit à 95,0 % a z = -0,7 et n'est pas marquée.
Ce que cet algorithme ne sait pas faire
- Sans 7 nuits mesurées de qualité non faible, aucune nuit n'est comparée : l'écran dit que la normale n'est pas encore connue.
- La normale suit tes propres nuits : une dérive lente de plusieurs semaines peut devenir ta « normale ».
- Les nuits sous 90 % comptent toutes les nuits qui ont un p90 positif, y compris des nuits de qualité faible, alors que les nuits plus basses les excluent (voir les notes).
- Les seuils 88 % et 3 nuits sont des règles de Trévor ; le fichier indique « à valider par les HUG ».
- La moyenne d'une nuit saisie à la main compte comme une moyenne de montre.
Code : src/trevor/wearables/service.py (night_view, _night_pairs, _recent_oximeter, night_alert_due), src/trevor/conversation/night_screen.py (blocks, row, payload), src/trevor/wearables/crisis.py (_robust, _z, DROP_Z), data/emergency_thresholds.json, src/trevor/conversation/reminders.py (alerte douce, vers 1565)
Oxygène de la nuit : moyenne, creux, temps sous le seuil, indice de désaturation
Quand ta montre ou ta bague envoie une série de mesures d'oxygène pendant la nuit, Trévor la résume en quelques chiffres : moyenne, creux, part de la nuit sous 92, 90 et 88 %, et nombre de chutes par heure. Ces chiffres alimentent l'écran « Ma nuit » et ta normale. Ce n'est pas un dispositif médical validé.
Où tu le vois : Écran « Ma nuit » du bot (ligne de chaque nuit : oxygène moyen), application (GET /api/phone/nuit), courbes « Mes repères » (oxygène moyen, creux, temps sous 90 %, chutes par heure).
Ce que l’algorithme lit
- Mesures d'oxygène de la nuit (heure et SpO2 en %), valeurs gardées entre 50 et 100 (montre ou bague via l'application, Health Connect, export Apple Santé, Health Auto Export)
- Durée de la nuit à couvrir (temps endormi, sinon temps au lit) (sommeil de la même nuit)
- Part de la nuit en mouvement (0 à 1), si la source la donne (montre ou application)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
THRESHOLDS | (92, 90, 88) | Seuils du temps cumulé sous la saturation | src/trevor/wearables/night.py:26 |
MAX_GAP_S | 300 | Au-delà de 5 minutes sans mesure, le temps n'est pas compté comme mesuré | src/trevor/wearables/night.py:27 |
ODI_MAX_STEP_S | 60 | Pas typique maximal pour calculer un indice de désaturation | src/trevor/wearables/night.py:28 |
ODI_MIN_VALID_MIN | 120 | Minutes valides minimales pour un indice | src/trevor/wearables/night.py:29 |
BASELINE_WINDOW_S | 120 | Niveau de référence d'un événement : maximum des 2 minutes précédentes | src/trevor/wearables/night.py:30 |
MAX_SAMPLES | 20000 | Nombre maximal de mesures lues | src/trevor/wearables/night.py:35 |
drop dans _count_events | 3 et 4 points | Un événement est une baisse d'au moins 3 (odi3) ou 4 points (odi4) sous la référence, tenue sur deux mesures | src/trevor/wearables/night.py:93-94,110-123 |
Ce qui est affiché
Un résumé par nuit : mean (moyenne, 1 décimale), min (creux), p92, p90, p88 (% du temps valide), odi3 et odi4 (par heure, seulement si le pas est de 60 s ou moins et la mesure valide d'au moins 2 h), valid_min, coverage, motion, qualité. Un événement se termine quand la saturation remonte à moins de (seuil - 1) points de sa référence ; une seule mesure basse isolée ne compte pas.
Un exemple chiffré
Calcul exécuté avec le code : 480 mesures, une par minute, à 96 %, dont 3 mesures à 91 % et 10 mesures à 89 %, nuit de 480 minutes. Résultat : moyenne 95,8 ; creux 89 ; p92 2,7 % ; p90 2,1 % ; p88 0 % ; odi3 et odi4 à 0,2 par heure ; couverture 1,0 ; qualité « bonne ».
Ce que cet algorithme ne sait pas faire
- Les chiffres dépendent de l'appareil : un capteur grand public se trompe plus facilement quand tu bouges.
- Une série espacée de plus de 5 minutes ne donne ni pourcentage de temps ni indice, seulement une moyenne et un minimum.
- Pas de reconstitution des trous : le temps sans mesure n'est pas compté, ce qui peut cacher une baisse pendant un trou.
- Un résumé reçu tel quel (Oura : moyenne seule ; Fitbit : moyenne et minimum) n'a ni temps sous le seuil ni indice.
Code : src/trevor/wearables/night.py (summarize_oxygen, _count_events, oxygen_from_aggregate), src/trevor/wearables/files.py (night_from_item), src/trevor/wearables/oura.py, src/trevor/wearables/fitbit.py
Qualité d'une nuit, nuits ignorées et choix de la source
Trévor note chaque nuit mesurée « bonne », « moyenne » ou « faible » selon la durée mesurée, la couverture et le mouvement. Une nuit « faible » reste visible mais n'entre dans aucun calcul (ta normale, nuits plus basses, courbes). Quand plusieurs sources décrivent la même nuit, il garde la meilleure.
Où tu le vois : Écran « Ma nuit » (avertissement sur la qualité quand une nuit est faible), courbes « Mes repères », modèle de risque (qui ignore aussi les nuits faibles).
Ce que l’algorithme lit
- Résumé d'oxygène de la nuit (valid_min, couverture, mouvement, nombre de mesures) (calcul sur la série ou résumé de la source)
- Résumé du sommeil de la nuit (montre, bague, saisie)
- Date et heure d'une mesure (pour attribuer la mesure à une nuit) (montre)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
MIN_VALID_MIN | 120 | Sous 2 h de mesure valide, qualité faible | src/trevor/wearables/night.py:31 |
MIN_COVERAGE | 0.5 | Sous 50 % de la nuit couverte, qualité faible | src/trevor/wearables/night.py:32 |
MOTION_HIGH | 0.30 | Plus de 30 % de la nuit en mouvement : qualité faible | src/trevor/wearables/night.py:33 |
MOTION_MID | 0.15 | Plus de 15 % en mouvement : qualité moyenne | src/trevor/wearables/night.py:34 |
couverture moyenne | 0.8 | Série couverte à moins de 80 % : qualité moyenne | src/trevor/wearables/night.py:131 |
nombre de mesures | 30 | Moins de 30 mesures : qualité moyenne | src/trevor/wearables/night.py:131 |
heures de nuit | 20 h à 10 h | Fenêtre d'attribution d'une mesure à une nuit | src/trevor/wearables/night.py:50-58 |
Ce qui est affiché
Étiquette de qualité par nuit (bonne, moyenne, faible). `oxy_usable` et `sleep_usable` renvoient la nuit seulement si la qualité n'est pas « faible » (et, pour l'oxygène, si une moyenne existe). Une saisie à la main reçoit 480 minutes valides, donc « moyenne ».
Un exemple chiffré
Calcul exécuté avec le code : la série de 480 mesures de l'exemple précédent (couverture 1,0, 480 minutes valides, 480 mesures) donne « bonne ». Un résumé sans série (moyenne et minimum seuls) donne au mieux « moyenne ».
Ce que cet algorithme ne sait pas faire
- La qualité ne contrôle pas si le capteur était bien posé ni si la peau foncée a faussé la lumière : elle ne voit que la durée, la couverture et le mouvement.
- Un résumé reçu d'une source ne dit rien de la couverture : Trévor ne peut pas le juger plus finement.
- Une nuit « faible » disparaît des calculs sans que tu en sois prévenu nuit par nuit ; seul un avertissement général s'affiche quand au moins une nuit des 14 jours est faible.
- Le sommeil reçoit toujours « moyenne » ou « bonne » (la qualité est recalculée à chaque lecture) : `sleep_usable` n'écarte donc jamais une nuit de sommeil.
Code : src/trevor/wearables/night.py (assign_night, quality_of, oxy_usable, sleep_usable, scalars, by_date, _oxy_rank, _sleep_rank, clean_night), src/trevor/wearables/service.py (night_records)
Saisie à la main : oxygène de la nuit, oxymètre au doigt, nuit ressentie et heure du coucher
Quand ta montre n'envoie pas l'oxygène de la nuit, tu peux l'écrire toi-même, ainsi qu'une valeur d'oxymètre au doigt, ta nuit ressentie et l'heure approximative du coucher. Trévor range ces saisies comme des mesures, sans les corriger.
Où tu le vois : Bot : « 🫁 Mon oxygène (SpO2) », « Ma nuit » (bouton de saisie), « Ma journée » (question sur la nuit).
Ce que l’algorithme lit
- Deux ou trois nombres de 50 à 100 pour la nuit (moyenne, creux, pic éventuel) (déclaration dans le bot)
- Une valeur d'oxymètre entre 70 et 100 (déclaration dans le bot)
- Nuit ressentie (bien, moyen, mal) et tranche d'heure de coucher (avant 22 h, 22 h, 23 h, après minuit) (déclaration dans le bot)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
plage de saisie nuit | 50 à 100 | Chaque nombre de la saisie de nuit | src/trevor/conversation/night_screen.py:90 |
valid_min manuel | 480 | Minutes valides attribuées à une saisie manuelle | src/trevor/conversation/night_screen.py:132 |
plage oxymètre | 70 à 100 | Valeur d'oxymètre acceptée | src/trevor/conversation/spo2_screens.py:41 |
LOW | 92.0 (ppg_spo2.LOW) | Au-dessous, message de sécurité sur la valeur saisie | src/trevor/conversation/spo2_screens.py:24 |
KEEP (oxymètre) | 60 | Valeurs d'oxymètre gardées | src/trevor/conversation/spo2_screens.py:25 |
KEEP_NIGHTS | 60 | Nuits ressenties gardées | src/trevor/navigator/sleep.py:22 |
BAD_NIGHTS_ADVICE / ADVICE_WINDOW_DAYS | 3 / 7 | Nuits « mal » sur 7 jours avant le conseil | src/trevor/navigator/sleep.py:23-24 |
SELF_SLEEP_Z | bien +1,0 ; moyen 0 ; mal -1,0 | Nuit déclarée vue comme un écart, sur l'échelle des mesures de la montre (utilisé par la forme du jour) | src/trevor/navigator/sleep.py:26 |
Ce qui est affiché
Une nuit d'oxygène enregistrée (moyenne, creux, pic éventuel) visible dans « Ma nuit », une valeur d'oxymètre dans les courbes et les alertes de valeurs, une nuit ressentie rangée dans le profil. Sous 92 % : « Refais la mesure après deux minutes de repos, assis, les mains chaudes. Si la valeur reste sous 92 %, appelle maintenant. »
Un exemple chiffré
Calcul exécuté avec le code d'analyse du texte : « 94 88 97 » donne moyenne 94, creux 88, pic 97 ; « 93,5 90 » donne moyenne 93,5, creux 90, pas de pic ; « 96 » seul est refusé.
Ce que cet algorithme ne sait pas faire
- Rien ne vérifie que les nombres viennent d'un appareil : Trévor ne peut pas distinguer une moyenne réelle d'un chiffre recopié.
- La saisie est toujours attribuée à la date d'aujourd'hui ; saisir hier n'est pas possible depuis cet écran.
- Une saisie d'oxymètre nocturne et une valeur de la montre le même jour : la bague Oura ou la montre Fitbit prime dans les courbes du jour.
- Un oxymètre de pouls peut afficher une valeur trop haute sur peau foncée.
Code : src/trevor/conversation/night_screen.py (parse_night_values, on_night_enter), src/trevor/conversation/spo2_screens.py (parse_value, on_spo2_enter), src/trevor/navigator/sleep.py, src/trevor/conversation/daily_screen.py (screen_sleep_night, on_sleep_bed)
Sommeil de la nuit : durée, efficacité, éveils
Trévor reprend ce que ton appareil dit de ta nuit (durée endormie, temps au lit, éveils, stades) et calcule seulement ce qui peut l'être sans rien inventer, comme l'efficacité du sommeil. Il compare ensuite ta nuit à ta propre normale pour repérer une nuit fragmentée.
Où tu le vois : Écran « Ma nuit » (durée de sommeil de chaque nuit), courbes « Mes repères » (efficacité, éveils, sommeil profond), phrase de la forme du jour.
Ce que l’algorithme lit
- Début et fin du sommeil, minutes au lit, endormi, latence, éveils (WASO), nombre d'éveils, stades profond, léger, paradoxal (Oura, Fitbit, Health Connect, Apple Santé, Health Auto Export, Open Wearables, fichiers)
- Segments de sommeil (début, fin, stade) quand l'appareil les donne (Health Connect, Apple Santé)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
watch_sleep bonne | 85 | Efficacité à partir de laquelle la montre est dite « bonne » | src/trevor/wearables/service.py:1103 |
watch_sleep mauvaise | 75 | Efficacité sous laquelle la montre est dite « mauvaise » | src/trevor/wearables/service.py:1103 |
seuil de fragmentation | 1.5 | Écarts de ta normale (éveils en hausse ou efficacité en baisse) | src/trevor/wearables/service.py:1106-1107,1109 |
MIN_SD sleep_eff / sleep_waso | 3.0 / 10.0 | Écarts-types minimaux de la normale pour l'efficacité et les éveils | src/trevor/wearables/crisis.py:164-165 |
BASELINE_DAYS | 30 | Nuits antérieures utilisées pour la normale | src/trevor/wearables/crisis.py:121 |
MIN_BASELINE | 7 | Nuits mesurées nécessaires pour une normale | src/trevor/wearables/crisis.py:122 |
Ce qui est affiché
Par nuit : durées en minutes, efficacité en %, nombre d'éveils, stades si connus. À l'écran : la durée endormie au format « 7 h 00 », un indicateur de fragmentation (utilisé dans la vue) et, avec la réponse « As-tu bien dormi ? », un signe 🔄 quand la montre et ta réponse divergent (réponse « oui » avec efficacité sous 75 %, ou « non » avec efficacité d'au moins 85 %).
Un exemple chiffré
Calcul exécuté avec le code : 480 minutes au lit et 420 minutes endormi, sans efficacité fournie, donnent une efficacité de 88 % (100 x 420 / 480) et une qualité « bonne ». 88 % est au-dessus de 85 %, donc la montre est « bonne ».
Ce que cet algorithme ne sait pas faire
- Une valeur absente reste absente : sans segment « éveillé », Trévor n'affiche aucun réveil plutôt que zéro.
- Les stades profond, léger et paradoxal dépendent de l'appareil, et les montres grand public les estiment avec une marge d'erreur.
- Les noms de champs de Open Wearables et de Health Auto Export sont indiqués dans le code comme plausibles et non vérifiés sur un export réel (openwearables.py:81 ; files.py:488).
- Une sieste ne remplace pas la nuit pour Oura (seul le type « long_sleep » est lu) ; pour Samsung, les durées de plusieurs sessions d'un même jour s'additionnent.
Code : src/trevor/wearables/night.py (sleep_summary, sleep_from_segments, normalise_stage), src/trevor/wearables/service.py (night_view), src/trevor/conversation/night_screen.py (row), src/trevor/wearables/oura.py, src/trevor/wearables/fitbit.py
Estimation de l'oxygène par l'appareil photo du téléphone (expérimentale)
Le téléphone pose ton doigt sur l'objectif et le flash, mesure comment la lumière pulse, et envoie à Trévor un rapport R, la qualité du signal et le pouls. Trévor convertit R en une estimation de SpO2 avec une fourchette, plus large tant que tu n'as pas calibré avec un oxymètre de référence. C'est expérimental et ce n'est pas un dispositif médical validé.
Où tu le vois : Application Coach Drépano (carte « SpO2 par la caméra ») et bot (« Mon oxygène » : dernière estimation, fourchette et phrase de verdict).
Ce que l’algorithme lit
- R = (AC rouge / DC rouge) / (AC bleu / DC bleu), calculé sur le téléphone (l'image reste sur le téléphone) (photo du doigt avec flash)
- Qualité du signal de 0 à 1 et pouls (30 à 220) (application)
- Valeur d'un oxymètre de pouls de référence (70 à 100), facultative, et couleur de référence (bleu ou vert) (déclaration dans l'application)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
R_RANGE | (0.2, 2.5) | Plage plausible de R | src/trevor/media/ppg_spo2.py:24 |
DEFAULT_A, DEFAULT_B | 110.0, 25.0 | Droite universelle : SpO2 = 110 - 25 x R | src/trevor/media/ppg_spo2.py:25 |
DEFAULT_MARGIN | 8.0 | Demi-largeur de la fourchette sans calibrage (points de SpO2) | src/trevor/media/ppg_spo2.py:26 |
MIN_QUALITY | 0.5 | Qualité minimale du signal | src/trevor/media/ppg_spo2.py:27 |
MIN_PAIRS | 3 | Couples (R, oxymètre) pour une droite personnelle | src/trevor/media/ppg_spo2.py:28 |
LOW | 92.0 | Seuil du verdict « basse » | src/trevor/media/ppg_spo2.py:29 |
KEEP | 90 | Mesures gardées par personne | src/trevor/media/ppg_spo2.py:30 |
marge calibrée | max(2, 2 x écart résiduel) | Fourchette avec une droite personnelle (écart résiduel au moins 1) | src/trevor/media/ppg_spo2.py:48,58 |
plage des couples | R 0,2 à 2,5 ; SpO2 70 à 100 | Couples gardés pour l'ajustement | src/trevor/media/ppg_spo2.py:35 |
Ce qui est affiché
Une valeur arrondie, une fourchette (bas et haut), si elle est calibrée, et un verdict. Phrases du bot : « Valeur basse. », « La fourchette est trop large pour conclure. » ou « Aucune alerte. Cette estimation ne remplace pas un oxymètre de pouls. » Le verdict « normale » exige une droite personnelle et que le bas de la fourchette reste au moins à 92. Sous 92 ou en cas de malaise, un oxymètre de pouls puis l'équipe soignante ou le 144 passent avant tout.
Un exemple chiffré
Calcul exécuté avec le code : R = 0,6 et qualité 0,8 sans calibrage donnent 95 % (110 - 25 x 0,6), fourchette de 87 à 100 %, verdict « incertaine ». Avec quatre couples (0,5 ; 98), (0,7 ; 93), (0,9 ; 88), (0,6 ; 95,5), la droite devient 110,5 - 25 x R avec un écart résiduel de 1 ; R = 0,6 donne 96 % entre 94 et 98 %, verdict « normale » ; R = 0,95 donne 87 % entre 85 et 89 %, verdict « basse ».
Ce que cet algorithme ne sait pas faire
- Le capteur d'un téléphone n'est pas conçu pour mesurer l'oxygène : doigts froids, ongles vernis, mouvement et lumière ambiante faussent le résultat.
- La droite universelle n'a pas été validée, en particulier sur peau foncée ; la mélanine absorbe le bleu, c'est pourquoi le calibrage personnel est la base de la mesure.
- Le calibrage est faussé si ton oxymètre de référence surestime l'oxygène sur peau foncée : l'estimation hérite alors de ce biais.
- La fourchette ne s'appuie que sur l'écart résiduel de tes couples : avec 3 couples, elle peut paraître trop étroite par hasard (plancher à 2 points).
- Aucun lien avec les nuits : cette mesure ne passe pas dans « Ma nuit » ni dans les alertes de valeurs.
Code : src/trevor/media/ppg_spo2.py (fit, estimate, add_reading, view), src/trevor/signals.py (spo2_cam_reading, last_oximeter), src/trevor/conversation/spo2_screens.py (screen_spo2), docs/SPO2_CAMERA.md
Qualité des mesures de la montre : bonne, moyenne ou insuffisante
Trévor compte sur 14 jours combien de journées ont assez de mesures utiles, et en déduit si ta montre te donne des mesures « bonnes », « moyennes » ou « insuffisantes ». Cette étiquette sert à taire une conclusion fragile et à montrer la fiabilité au poignet et dans le bot.
Où tu le vois : Champ « measure_quality » de l'écran « Ma santé » au poignet et dans l'application.
Ce que l’algorithme lit
- Lignes quotidiennes fusionnées des 14 derniers jours (montre ou bague)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
WINDOW_DAYS | 14 | Fenêtre | src/trevor/wearables/mesure.py:16 |
MIN_NIGHT_COVERAGE_MIN | 120 | Sommeil minimal d'une journée exploitable | src/trevor/wearables/mesure.py:17 |
GOOD_DAYS | 10 | Journées pour « bonne » | src/trevor/wearables/mesure.py:19 |
MEDIUM_DAYS | 6 | Journées pour « moyenne » | src/trevor/wearables/mesure.py:20 |
Ce qui est affiché
Une étiquette (bonne, moyenne, insuffisante), le nombre de jours exploitables, les trous. L'étiquette ne dit rien de la justesse des valeurs, seulement de leur régularité.
Ce que cet algorithme ne sait pas faire
- Le comptage mesure la présence des données, pas leur exactitude.
- Une montre mal portée mais qui produit toujours deux mesures est jugée « bonne ».
Code : src/trevor/wearables/mesure.py (usable, assess), src/trevor/wearables/watch_summary.py (_measure_quality)
Séries alignées du « tableau de bord de ta vie »
Trévor met sur le même axe des jours ce que tu vis (douleur, humeur, forme, fatigue, jours de crise), ton corps (montre, nuits, laboratoire), l'environnement, tes soins et des repères d'événements. Il ne calcule ni moyenne ni interpolation : un jour sans mesure reste vide.
Où tu le vois : Vue santé (lifecourse/health_view.py, jusqu'à 366 jours), recommandations du navigateur (90 jours), associations de findings.py et recherche longitudinale (180 jours) ; les écrans exacts qui les affichent ne sont pas tous relus.
Ce que l’algorithme lit
- Douleur, humeur, fatigue, sensation de température (froid, chaud, fièvre), température mesurée (suivi du jour, observations rapides)
- Épisodes de crise, séjours à l'hôpital, transfusions (déclaration, dossier)
- Mesures de la montre, nuits (oxygène moyen, creux, temps sous 90 %, chutes par heure, efficacité, éveils, sommeil profond) (montre, bague)
- Environnement du jour (Open-Meteo, CAMS)
- Laboratoire, indice de jaune de l'œil, eau, prises de traitement, antalgique de secours, gestes personnels (dossier, déclaration)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
MAX_DAYS | 180 | Fenêtre maximale par défaut | src/trevor/navigator/series.py:21 |
MIN_DAYS | 14 | Fenêtre minimale | src/trevor/navigator/series.py:22 |
seuil de douleur | 7 | Un jour avec une douleur notée de 7 ou plus compte comme jour de crise | src/trevor/navigator/series.py:157 |
MAX_MISSED_LISTED | 300 | Doses manquées listées | src/trevor/navigator/series.py:76 |
unités | pas ; min ; bpm ; ms ; % ; /min ; °C ; dB(A) ; /h | Unités des séries de la montre et des nuits | src/trevor/navigator/series.py:29-47 |
Ce qui est affiché
Pour chaque série, des valeurs par jour (seulement les jours mesurés), des libellés avec leur unité et leur groupe, des événements, l'attribution « Open-Meteo, CAMS (Copernicus) ». Aucun chiffre composite.
Ce que cet algorithme ne sait pas faire
- Un jour de douleur notée à 7 ou plus devient « jour de crise » même sans épisode déclaré : c'est une règle de Trévor, pas un diagnostic.
- Les nuits à qualité faible n'apparaissent pas (voir l'algorithme sur la qualité).
- Les valeurs de la montre dépendent des biais des capteurs.
- Toute la lecture des nuits est dans un bloc qui ignore silencieusement les erreurs : une panne de lecture des nuits laisse la courbe vide sans message.
Code : src/trevor/navigator/series.py (build), src/trevor/wearables/day_view.py (series, monitor), src/trevor/lifecourse/health_view.py (_nav), src/trevor/navigator/reco_flow.py (vers 243), src/trevor/research_longitudinal.py (vers 589)
Le seuil d'oxygène bas (92 %) et les seuils proches : où ils s'appliquent et comment les régler
Trévor utilise plusieurs seuils d'oxygène à des endroits différents : 92 % pour une valeur isolée, 90 % et 88 % pour le temps passé la nuit, et 88 % pour l'urgence. Le 92 % ne se règle pas ; tu peux seulement fixer ta propre zone habituelle, qui change quand une alerte part.
Où tu le vois : Messages de saisie d'oxymètre, estimation par caméra, alertes de valeurs, signaux de la montre, « Ma nuit ».
Ce que l’algorithme lit
- Une valeur d'oxygène (oxymètre, caméra, montre) ou une moyenne de nuit (voir les autres algorithmes)
- Ta zone habituelle (bas, haut) si tu en as fixé une (carte « Alertes de valeurs »)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
LOW | 92.0 | Seuil de la caméra et du message d'oxymètre | src/trevor/media/ppg_spo2.py:29 |
Metric spo2 low | 92 | Norme générale de la saturation dans les alertes de valeurs | src/trevor/value_alerts.py:68 |
signals spo2 | < 92 | Signal « SpO2 nocturne » | src/trevor/wearables/service.py:486 |
qualitative spo2 | < 92 | Phrase de tendance (moyenne récente) | src/trevor/wearables/service.py:444 |
THRESHOLDS | (92, 90, 88) | Temps cumulé sous ces seuils chaque nuit | src/trevor/wearables/night.py:26 |
ABS_LOW_NIGHT | 92.0 | Moyenne de nuit sous laquelle le modèle de risque compte une nuit basse | src/trevor/wearables/crisis.py:190 |
night_spo2_very_low | 88 | Urgence : moyenne de nuit ou oxymètre à 88 % ou moins | data/emergency_thresholds.json:11 |
Ce qui est affiché
Un même mot « bas » peut venir de seuils différents selon l'écran. Aucun écran ne te permet de changer 92 % ni 88 %. Ta zone habituelle personnelle (ou celle de ton soignant) modifie seulement le niveau de l'alerte de valeur.
Un exemple chiffré
Calcul exécuté avec le code : une valeur de 91 % sans zone fixée est une « alerte » ; avec une limite basse fixée à 90 %, la même valeur devient « habituel pour toi » ; avec une limite basse fixée à 94 %, elle reste « alerte ». Une valeur de 93 % avec une limite basse à 94 % est « à surveiller ».
Ce que cet algorithme ne sait pas faire
- Le même nombre 92 est écrit à au moins six endroits du code, sans constante commune : un changement futur devrait être fait partout.
- Le seuil d'urgence 88 % et le nombre de 3 nuits sont lus dans data/emergency_thresholds.json ; les autres 92 % sont écrits en dur.
- Un oxymètre peut afficher une valeur trop haute sur peau foncée : un chiffre à 93 % ne prouve pas que tout va bien.
Code : src/trevor/media/ppg_spo2.py, src/trevor/conversation/spo2_screens.py (on_spo2_enter), src/trevor/value_alerts.py, src/trevor/wearables/service.py (signals, qualitative_summary, night_view), src/trevor/wearables/night.py, src/trevor/wearables/crisis.py, data/emergency_thresholds.json
Zone habituelle de chaque mesure et alertes de valeurs
Trévor lit ta dernière valeur face à deux repères : la norme générale de l'adulte et ta zone habituelle, apprise sur tes propres valeurs ou fixée par toi ou ton soignant. Selon que la valeur sort de l'un, des deux ou d'aucun, il affiche « alerte », « à surveiller », « habituel pour toi » ou « rien à signaler ». Ce n'est pas un diagnostic.
Où tu le vois : Carte « Alertes de valeurs » du tableau de bord (patient et soignant), message poussé du bot pour le niveau « alerte » (une fois par mesure et par date, désactivable), alertes du tableau de bord pour fatigue et laboratoire.
Ce que l’algorithme lit
- Une valeur par jour de la montre : oxygène nocturne, pouls au repos, fréquence respiratoire, HRV, écart de température cutanée, sommeil, pas, bruit ambiant (montre, bague, oxymètre saisi (lues seulement si tu as activé la lecture des données de l'objet connecté))
- Fatigue déclarée sur 10 (suivi du jour ou geste rapide)
- Limites fixées (bas, haut, par le patient ou le soignant) (carte du tableau de bord)
- Résultats de laboratoire (autres algorithmes de Trévor) (dossier)
Le calcul, étape par étape
Les valeurs utilisées
| Nom dans le code | Valeur | Rôle | Où |
|---|---|---|---|
LEARN_K | 2.5 | Largeur de la zone apprise en écarts robustes | src/trevor/value_alerts.py:41 |
MIN_WEAR, WEAR_DAYS | 10, 90 | Valeurs de montre pour apprendre une zone et fenêtre en jours | src/trevor/value_alerts.py:42 |
spo2 | norme basse 92 ; plancher 0,7 ; fraîcheur 3 j ; alerte si seule | Saturation nocturne : sous 92 % hors norme ; sans zone personnelle la lecture est déjà « alerte » | src/trevor/value_alerts.py:68 |
resting_hr | 50 à 100 bpm, deux sens, plancher 3 | Pouls au repos | src/trevor/value_alerts.py:69 |
respiratory_rate | 12 à 20 /min, deux sens, plancher 1 | Fréquence respiratoire | src/trevor/value_alerts.py:70 |
hrv | sans norme, sens bas, plancher 5 ms | Variabilité cardiaque : seul l'écart à ta zone compte | src/trevor/value_alerts.py:71 |
temp_deviation | haut 0,5 °C, sens haut, plancher 0,2 | Écart de température cutanée | src/trevor/value_alerts.py:72 |
sleep_minutes | bas 300 min, sens bas, plancher 30 | Sommeil : sous 5 h | src/trevor/value_alerts.py:73 |
steps | sans norme, sens bas, plancher 1 500 | Pas par jour | src/trevor/value_alerts.py:74 |
fatigue | haut 7/10, sens haut, plancher 1 | Fatigue déclarée : au-delà de 7/10 (repère à faire valider) | src/trevor/value_alerts.py:75 |
noise_db | haut 70 dB(A), plancher 3 | Bruit ambiant moyen du jour | src/trevor/value_alerts.py:76 |
PLAUSIBLE | oxygène 50 à 100 ; pouls 25 à 250 ; sommeil 0 à 960 min ; pas 0 à 60 000 | Au-delà, la valeur n'entre pas dans la zone habituelle | src/trevor/value_alerts.py:98-99 |
Ce qui est affiché
Une ligne par mesure avec niveau (alerte, à surveiller, habituel pour toi, rien à signaler), sens (sous ou au-dessus), norme et zone habituelle, triée des plus préoccupantes aux moins. Exemple de phrase de niveau « alerte » : « Saturation en oxygène nocturne : 91 %, sous la norme (92 %) et sous ta zone habituelle (93,65 %). Parle-en à ton équipe soignante. »
Un exemple chiffré
Calcul exécuté avec le code : 12 nuits entre 95,0 et 96,0 % (médiane 95,5 ; zone apprise de 93,65 à 97,35) puis une valeur à 91 % : niveau « alerte ». Si tu fixes toi-même une limite basse à 90 %, la même valeur à 91 % devient « habituel pour toi » : elle est sous la norme de 92 mais au-dessus de ta limite, donc aucun message n'est envoyé. Avec une seule valeur à 91 % et aucun historique : « alerte » aussi, car la saturation est traitée à part.
Ce que cet algorithme ne sait pas faire
- Une limite que tu fixes remplace la zone apprise et peut faire disparaître une alerte : une limite basse à 90 % pour l'oxygène transforme 91 % en « habituel pour toi ».
- Le seuil de 92 % de la norme n'est pas réglable : seule la zone personnelle l'est (route /moi/.../limites pour toi, /soignant/patient/.../limites pour le soignant).
- Une dérive lente de plusieurs semaines peut s'installer dans la zone apprise sans alerte.
- Les mesures de la montre ne sont lues que si tu as activé la lecture des données de ton objet connecté.
- La zone est calculée à partir de la médiane de tes valeurs et ignore le moment de la nuit ; une valeur par jour seulement.
Code : src/trevor/value_alerts.py (METRICS, learn, evaluate, set_limit, build, describe, unsent), src/trevor/dashboard/server.py (patient_limits, clinician_limits, vers 6939-6970), src/trevor/conversation/reminders.py (value_alerts)
