5 points par GN⁺ 2024-03-05 | 1 commentaires | Partager sur WhatsApp
  • Un ingénieur diagnostiqué avec un diabète de type 1 en 2020 a créé un système personnel de monitoring basé sur Go afin de traiter la gestion de sa glycémie comme une réponse à incident
  • En l’absence d’API ou de SDK officiel pour Libre, l’intégration directe était difficile, mais il a trouvé un chemin permettant d’envoyer les données de glycémie vers un endpoint externe toutes les 2 minutes via Miao Miao et l’app Tomato
  • Avec un serveur echo en Go et un déploiement sur Encore, il a vérifié le format des requêtes Tomato, converti les valeurs SGV et les a affichées dans un tableau de bord Grafana sous forme de jauge de glycémie en temps réel
  • Un bot Telegram permet d’ajouter des annotations de contexte comme les repas, l’exercice ou les injections d’insuline, tandis qu’un cron exécuté toutes les 5 minutes crée un incident incident.io lorsque la glycémie passe sous un seuil donné
  • Ce workflow, complété par des alertes, de l’escalade et des rapports, fonctionne comme un système d’observabilité de santé personnelle qui évite d’avoir à gérer seul une hypoglycémie ou une absence de mesures

Traiter le diabète de type 1 comme un problème de réponse à incident

  • Le diabète de type 1 est une maladie auto-immune dans laquelle le pancréas produit peu ou pas d’insuline, nécessaire pour transformer les glucides en énergie
  • L’insuline doit être apportée par injection, et la dose varie selon ce que l’on mange et de nombreux autres facteurs
  • Le type 1 n’est pas une maladie causée par le mode de vie, et il n’existe actuellement aucun traitement curatif
  • La glycémie doit être surveillée en continu
    • Si elle reste trop élevée trop longtemps, cela peut entraîner des lésions d’organes et une réduction de l’espérance de vie
    • Si elle est trop basse, elle peut être fatale en peu de temps
    • Lorsque la glycémie descend trop bas, il peut devenir impossible de manger ou de boire en sécurité, ce qui peut nécessiter l’aide d’une autre personne
  • À chaque aliment ou boisson, il faut calculer la quantité de glucides et la dose d’insuline nécessaire, et même une courte promenade doit tenir compte de la quantité d’insuline active dans l’organisme
  • Une situation où la visibilité sur la glycémie disparaît peut être traitée comme un état d’observabilité nulle dans un système de production
    • Dans un contexte professionnel, on déclarerait un incident et on ne le clôturerait pas tant que la visibilité n’est pas rétablie
    • Une glycémie basse est le premier signal que quelque chose ne va pas et demande une action immédiate

Trouver un chemin de données avec Libre, Miao Miao et Tomato

  • Le dispositif Libre, fixé au bras, permet de lire la glycémie en approchant un téléphone
    • Le dispositif doit être remplacé toutes les 2 semaines
    • Si la glycémie passe sous une certaine ligne rouge, il faut consommer des glucides
    • Si elle sort de la zone verte, on peut envisager une action comme l’administration d’insuline
  • L’exercice, la prise de poids et la maladie modifient la sensibilité à l’insuline, ce qui fait de la gestion de la glycémie une cible en mouvement permanent
  • Lorsque Libre affiche une erreur, il devient impossible de lire la glycémie depuis le dispositif et de recevoir des alertes de niveau dangereux
  • Libre est un dispositif fermé, ce qui rend difficile la récupération directe des données sans API ni SDK
  • Miao Miao se fixe au-dessus de Libre, effectue un scan environ toutes les 2 minutes et envoie les résultats à l’app Tomato
    • Même lorsque l’app Libre officielle affiche une erreur, le chemin Miao Miao continue de publier des données
    • L’app officielle semblait considérer les variations rapides de glycémie comme des valeurs aberrantes et ne pas envoyer ces données, alors que l’utilisateur voulait pouvoir les évaluer lui-même
  • L’app Tomato dispose d’une fonction qui publie la glycémie toutes les 5 minutes sous forme d’événement Google Calendar, ce qui permettait de l’afficher dans une complication Apple Watch

Vérifier les requêtes Tomato avec un serveur echo en Go

  • Les réglages de l’app Tomato comprenaient un champ d’URL de synchronisation de données pour Nightscout
  • En renseignant l’adresse d’un serveur web géré directement au lieu de l’URL Nightscout, le chemin suivant est apparu dans les logs de la passerelle
/id/e1d67817-4591-4e8e-9bca-58a07a1087d8/api/v1/devicestatus
  • Pour inspecter le corps des requêtes, il a écrit un simple serveur echo en Go
  • Il a utilisé encore.dev pour le déploiement et l’exécution, ce qui lui a permis d’opérer le système de monitoring gratuitement
// encore:api public raw method=POST path=/id/:id/api/v1/devicestatus
func Echo(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", req.Header.Get("Content-Type"))
    if _, err := io.Copy(w, req.Body); err != nil {
        http.Error(w, "Failed to echo request", http.StatusInternalServerError)
        return
    }
}
  • Un serveur echo renvoie tel quel les données envoyées par le client ; il est utile pour résoudre des problèmes réseau ou tester le comportement d’une application
  • En vérifiant d’autres requêtes de la même manière, il a obtenu une réponse contenant les données de glycémie
- date: 1696171541297
sgV: 73
delta: 0
sysTime: 1696171541381
dateString: "2023-10-01T14:45:41.297Z"
_id: "dOUXaI8HcaulCGrQfxe23UE0"
type: "sgv"
device: "Tomato"
direction: "Flat"
  • sgV correspond à la valeur de glycémie, qu’il divise par 18 pour l’adapter à l’unité utilisée au Royaume-Uni
  • La réponse inclut aussi la date, l’heure et la direction de la tendance
  • Cet appel se produit toutes les 2 minutes

Tableau de bord Grafana et jauge de glycémie

  • Les valeurs de glycémie reçues ont été configurées comme une Gauge metric
  • Une jauge est une métrique représentant une valeur unique pouvant monter ou descendre, utilisée pour mesurer des valeurs variables comme l’utilisation mémoire, le nombre de requêtes simultanées ou la température
  • La valeur de glycémie est convertie et enregistrée avec newValue / 18
var BloodSugar = metrics.NewGauge[float64]{
    name: "blood_sugar",
    metrics.GaugeConfig{},
}
BloodSugar.Set(float64(newValue) / 18)
if err := insertReading(ctx, newValue); err != nil {
    rlog.Error(msg: "failed to insert blood sugar, proceeding", keysAndValues: "db_err", err)
}
  • Les données de glycémie sont également stockées dans Postgres en mode best effort
    • En cas d’échec d’écriture en base, le système se contente de journaliser l’erreur et continue, afin de ne pas faire échouer le reste de la logique
  • Le tableau de bord Grafana affiche en temps réel une jauge de glycémie mise à jour toutes les 2 minutes
  • La plage cible de glycémie se situe idéalement entre 4 et 9
  • En partageant le tableau de bord ou en installant un écran à la maison, il devient possible de vérifier l’état de la glycémie d’un coup d’œil

Ajouter du contexte à la glycémie avec un bot Telegram

  • Les chiffres de glycémie seuls ne suffisent pas ; comme dans le monitoring de systèmes complexes, le contexte est important
  • Même si la glycémie augmente juste après un repas, cela peut ne pas être immédiatement inquiétant si une injection d’insuline a déjà été faite
  • Grafana prend en charge les annotations, mais devoir se connecter pour les ajouter manuellement est contraignant
  • Il a créé un bot Telegram configuré pour ajouter une annotation via webhook à chaque message reçu
// encore:api public raw method=POST path=/webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
    body, err := io.ReadAll(req.Body)
    if err != nil {
        http.Error(w, "could not read request body", http.StatusBadRequest)
        return
    }
    defer req.Body.Close()

    var update Update
    err = json.Unmarshal(body, &update)
    if err != nil {
        http.Error(w, "could not unmarshal JSON", http.StatusBadRequest)
        return
    }
}
  • Le webhook reçoit la requête, valide le message, désérialise le JSON, puis renvoie le résultat du traitement à Telegram
  • Après validation du message, il parse un entier et appelle le service d’annotation
  • Le service d’annotation ajoute des tags en fonction de l’activité
func getTags(ctx context.Context, activity string) []string {
    a := strings.ToLower(activity)
    switch a {
    case "walk", "run", "ran", "gym":
        return []string{"exercise"}
    case "eat", "ate":
        return []string{"food eaten"}
    case "inject":
        return []string{"inject"}
    default:
        return []string{"other"}
    }
}
  • Dans Grafana, il est possible de définir des couleurs par tag et de configurer des requêtes d’annotations
  • Lorsque des contextes comme les repas, l’exercice ou les injections d’insuline sont affichés sur le graphique, la personne concernée et celles qui consultent le tableau de bord peuvent interpréter plus facilement la situation glycémique

Transformer une hypoglycémie en incident

  • La visibilité sur la glycémie était acquise, mais sans alertes, il restait difficile de réagir en temps réel
  • Selon les consignes reçues d’une infirmière, il faut commencer à agir lorsque la glycémie descend sous 4
  • Il a écrit un petit cron qui vérifie la mesure toutes les 5 minutes et déclenche un incident si elle passe sous la limite basse prédéfinie
var _ = cron.NewJob(
    id: "monitor-blood",
    cron.JobConfig{
        Title: "monitor blood to check if there is reason to open an incident",
        Every: 5 * cron.Minute,
        Endpoint: BloodIncidentCron,
    },
)
if r < BloodLowerLimit {
    if err := triggerIncident(ctx); err != nil {
        return fmt.Errorf("failed to trigger an incident: %w", err)
    }
}
  • Le bot Telegram intègre aussi du code permettant d’ouvrir manuellement un incident avec le message "i need help"
  • Lorsqu’un incident est déclenché, un microservice séparé crée un incident dans incident.io
  • incident.io a été choisi parce qu’il ressemble le plus à l’outil d’incident interne de Cloudflare et qu’il est entièrement écrit en Go
payload := Payload{
    IdempotencyKey: idemKey.String(),
    Mode: incidentModeStandard,
    Name: fmt.Sprintf("Matt's blood sugar is currently #%s", blood),
    SeverityID: incidentSeverityCritical,
    Summary: "Matt's blood sugar is low!",
    Visibility: "public",
}
  • Utiliser un véritable outil d’incident permet de configurer des politiques d’escalade et de consulter des rapports, par exemple le temps passé en état d’incident
  • Les workflows incident.io permettent de configurer des règles similaires à Zapier et d’envoyer des SMS aux abonnés
  • Dans l’exemple de workflow, l’ouverture d’un incident envoie un SMS à la personne concernée, puis si l’incident n’est pas clôturé pendant 20 minutes, il est automatiquement escaladé vers son ou sa partenaire ou ses frères et sœurs

Rapports et améliorations futures

  • Avec un outil d’incident, il est possible de voir dans des rapports combien d’incidents d’hypoglycémie se sont produits au fil du temps
  • Le graphique d’exemple utilise des données de démonstration pour le blog ; les données réelles sont heureusement bien plus ennuyeuses
  • Une tendance à la hausse des épisodes d’hypoglycémie peut indiquer que le traitement actuel n’est pas adapté et fournir une base pour en discuter avec un médecin
  • Les améliorations actuelles ou prévues sont les suivantes
    • Clôture automatique : aujourd’hui, les incidents sont clôturés manuellement afin d’examiner les données, mais certains ont été clôturés trop tard et ont déclenché une escalade ; ils pourraient donc être clôturés automatiquement après environ 15 minutes de glycémie stable
    • Dialogue avec les données : des années de données de glycémie sont stockées, et l’objectif est d’entraîner un LLM pour poser des questions comme « pourquoi est-ce que je baisse toujours à 15 h ? » et exploiter aussi d’autres données comme Google Calendar
    • Extension des graphiques : les graphiques sont actuellement simples, mais pourraient intégrer des indicateurs comme l’HbA1c, utilisée pour évaluer la réussite de la gestion du diabète
    • Renforcement de la prévention des pannes : puisque le système est important, plus il prévient d’échecs, mieux c’est

Un système personnel d’opérations de santé construit par le code

  • Au début du diagnostic de type 1, il craignait que la maladie rende sa vie difficile
  • Ce projet l’aide à comprendre, gérer et monitorer son diabète de type 1
  • Il traite la gestion de la glycémie comme un système distribué, en y ajoutant observabilité, alertes, incidents, escalades et rapports pour en faire un système personnel d’exploitation
  • La capacité à coder permet d’automatiser dans une certaine mesure la gestion d’une maladie qui, jusque dans les années 1920, équivalait à une condamnation à mort

1 commentaires

 
GN⁺ 2024-03-05
Avis sur Hacker News
  • Je vis avec le diabète depuis 16 ans, et j’aime beaucoup le ton de l’auteur, que je respecte. Quand il se sentira triste ou en colère à cause de la maladie, j’espère qu’il relira ce texte et se souviendra du moment présent, où il était convaincu de pouvoir tout encaisser.
    Ce n’est pas facile. Ni mentalement, ni concrètement ; dans mon cas, pendant des années, j’ai été presque « joyeusement hors de contrôle ».
    Rien qu’hier, pour la première fois de ma vie avec le diabète, j’ai vu 36 heures dans la plage cible et j’ai vraiment pleuré. 100 % de vert pendant 36 heures. Peut-être que j’ai enfin compris.
    Quelques années plus tard, ma qualité de vie a bondi d’environ 60 % grâce à un micro-infuseur relié à un CGM, au partage d’expériences avec d’autres personnes diabétiques, à l’installation d’une VM NightScout pour voir ma glycémie et sa tendance partout — téléphone, montre, widget de bureau, réveil, frigo —, et au comptage des glucides avec une précision allemande, avec un bolus exactement 15 minutes avant le repas. Je déteste vraiment vivre comme ça, mais ça marche.
    Tiens bon. Ne lâche rien.

  • Le style d’écriture est vraiment excellent et c’était un plaisir à lire. Par coïncidence, je travaille dans le pentest, et l’un de mes collègues est atteint de diabète de type 1.
    En voyant le tableau dressé par cet article et la complexité que cela implique, je ressens encore plus d’empathie pour ce collègue qui, tout en surmontant ce genre de difficultés au quotidien, reste l’une des personnes les plus gentilles et les plus faciles d’approche de l’équipe.

    • On peut vivre une vie normale avec le diabète, et même devenir un joueur de tennis de tout premier plan : https://en.wikipedia.org/wiki/Alexander_Zverev#Personal_life
      Mais après avoir lu cet article, on mesure vraiment le niveau d’autodiscipline nécessaire pour y parvenir.
    • Si le « pentesting » consistait à tester des stylos à insuline, on pourrait plaisanter en disant qu’une partie des tests se fait peut-être au stylo et au papier.
      Bien sûr, il peut aussi s’agir de chercher à s’introduire dans des systèmes, comme dans les tests d’intrusion ; je me demande si c’est bien ce que vous faites.
    • On dirait que vous avez trouvé un bon employeur. Beaucoup d’entreprises n’embauchent pas les personnes malades, ou les licencient, et il est d’ailleurs courant de conseiller de ne pas partager ses informations médicales au travail.
      J’ai lu récemment le cas d’un employé que tout le monde pensait voir promu, mais qui ne l’a finalement pas été. Son seul tort avait été de dire brièvement à un collègue qu’il était épuisé de devoir sans cesse réparer sa voiture en panne.
      Le poste promu impliquait un certain niveau de trajets domicile-travail, et son manager aurait dit : « Je voulais te promouvoir, mais j’ai entendu dire que ta voiture n’était pas en bon état. »
  • Après la présentation de Matt à GopherConSG, nous avons parlé du problème du fait que nous ne possédons pas nos propres données. Ce qui m’a marqué, c’est la complexité du sujet côté fournisseur de données, c’est-à-dire les entreprises qui surveillent la glycémie, avec beaucoup de responsabilités juridiques à assumer ; on comprend aussi pourquoi les grandes entreprises hésitent à ouvrir l’accès.
    En revanche, il paraît assez injuste que les utilisateurs n’aient pas accès à des données qui leur appartiennent légitimement et qu’ils peuvent utiliser pour agir concrètement.

    • C’est quelque chose que je n’ai jamais compris. Est-ce comparable au fait d’acheter un stylo BIC en acceptant un contrat de licence obligatoire selon lequel toute l’entropie produite avec ce stylo appartient au fabricant de l’outil, et non à l’auteur des données ? Sans la personne, ces données n’existeraient pas.
  • J’ai créé quelque chose dans le même esprit hier : un plugin tmux qui affiche les données de glycémie sous forme d’icône d’état dans le terminal.
    Je suis aussi diabétique de type 1 et j’utilise un Dexcom comme CGM ; pour l’instant je l’ai fait fonctionner pour cet environnement, mais j’aimerais prendre en charge d’autres appareils et ajouter davantage de fonctionnalités. Si ça vous intéresse, c’est ici :
    https://github.com/Cian911/tmux-xdrip

    • Ce serait bien que Dexcom se synchronise directement avec la montre. J’attends ça depuis des années, mais ça consommerait sans doute beaucoup la batterie de la montre.
    • En tant que diabétique de type 1 qui vit dans tmux, c’est vraiment génial. Il faut que j’essaie ça au plus vite.
  • L’idée de Miao Miao est intéressante. En tant que diabétique de type 1, le Freestyle Libre est un appareil incroyable qui a vraiment changé ma vie, mais le logiciel est assez médiocre.
    J’ai signalé un bug il y a plus d’un an, et Abbott ne l’a toujours pas reconnu comme tel. Pourtant, on trouve beaucoup de signalements identiques en ligne et dans les avis de l’application sur Google Play.
    Pour les personnes intéressées, ou capables d’aider à faire reconnaître le problème par Abbott : le bug fait que mettre LibreLink dans la liste des applications exemptées du mode Ne pas déranger n’a aucun effet, et dès que l’on passe en mode Ne pas déranger, une alerte « alarmes indisponibles » apparaît immédiatement. Dans un environnement de travail, activer le mode Ne pas déranger coupe aussi les alarmes de glycémie, ce qui est gênant.

  • Dans un registre un peu lié, on m’a diagnostiqué il y a six mois une apnée obstructive du sommeil, et je dois utiliser une machine CPAP qui insuffle de l’air à pression constante pendant le sommeil pour empêcher l’obstruction des voies respiratoires. Ce n’est pas aussi critique qu’un diabète de type 1, mais ces machines enregistrent bien plus de logs que je ne l’imaginais.
    En lisant cet article, je me suis demandé s’il existait, côté apnée du sommeil, des bricolages similaires pour la surveillance ou pour les cas plus sévères.
    Je connais déjà OSCAR et je l’utilise avec beaucoup de gratitude, mais je suis curieux de savoir ce qu’il existe d’autre.
    1: https://www.sleepfiles.com/OSCAR/

    • Je dirais au contraire que c’est directement lié à la survie. La CPAP a changé ma vie, et une apnée du sommeil non traitée sur le long terme provoque des problèmes cardiaques et d’autres problèmes de santé.
      Lors de mon étude du sommeil, au pire moment, environ 48 événements d’arrêt respiratoire par minute ont été enregistrés. Quand la langue se replie dans les voies respiratoires, respirer devient assez difficile.
    • Si votre appareil est pris en charge, https://home.sleephq.com/ gère bien ces données.
  • C’est intéressant, mais je me demande pourquoi il n’a pas examiné les logiciels open source de ce domaine comme Nightscout, xDrip, etc.
    Ce n’est pas un nouveau problème, et beaucoup de gens l’ont déjà résolu avec des solutions bien plus riches en fonctionnalités et qui fonctionnent bien.

    • Je les ai bien regardés. Pour ce que je voulais faire, repartir de zéro me semblait plus rapide, et c’était aussi une expérience d’apprentissage intéressante.
  • Scott Hanselman parle depuis des années sur son blog et sur YouTube du diabète de type 1 et de divers hacks techniques. Il avait notamment bricolé un affichage de sa glycémie dans le prompt du terminal : https://www.youtube.com/watch?v=_meKUIm9NwA

  • Les passages « Pendant cette période, l’appareil ne permet pas de mesurer la glycémie et aucune notification n’est envoyée même si la glycémie atteint un niveau dangereux. Cette erreur avait l’habitude de survenir aux moments les plus stressants » et « En y regardant de plus près, il semblait que l’application principale n’aimait pas recevoir des données où la glycémie changeait brusquement au point de ressembler à une valeur aberrante » ressemblent à un bug potentiellement mortel.

    • La plupart des capteurs fonctionnent ainsi. On part du principe que le capteur est toujours exact, alors qu’en réalité ce n’est pas le cas. Par exemple, si l’on se retourne sur le capteur pendant son sommeil, la bandelette à glucose oxydase peut être davantage enfoncée dans le corps, ce qui modifie la lecture.
      À strictement parler, il ne faut pas prendre de décisions de traitement uniquement à partir des données d’un CGM.
      Avec les capteurs Dexcom, certaines applications peuvent contourner ce processus en récupérant les valeurs brutes. Avec Libre, du moins Libre 3, j’ai déjà vu l’application compléter les données plus tard lorsqu’elle estime, dans certaines situations, qu’il ne s’agissait pas d’une mauvaise lecture mais d’une glycémie en train de changer rapidement.
  • Ce n’est pas technologique, mais il existe aussi des chiens d’alerte diabétique.
    J’apprends récemment que des chiens bien dressés obtiennent de très bons résultats pour compléter les systèmes de surveillance et d’alerte technologiques en prévenant leur maître.