- Một kỹ sư được chẩn đoán mắc đái tháo đường type 1 vào năm 2020 đã xây dựng một hệ thống giám sát cá nhân dựa trên Go để xử lý việc quản lý đường huyết giống như ứng phó sự cố
- Do Libre không có API hay SDK chính thức nên khó tích hợp trực tiếp, nhưng anh đã tìm ra đường đi để gửi dữ liệu đường huyết tới endpoint bên ngoài mỗi 2 phút thông qua Miao Miao và ứng dụng Tomato
- Bằng echo server viết bằng Go và triển khai trên Encore, anh xác nhận định dạng request của Tomato, chuyển đổi giá trị SGV và hiển thị trên dashboard Grafana dưới dạng đồng hồ đo đường huyết theo thời gian thực
- Bot Telegram dùng để để lại chú thích ngữ cảnh như bữa ăn, vận động, tiêm insulin; cron chạy mỗi 5 phút sẽ tạo incident trên incident.io nếu đường huyết tụt xuống dưới ngưỡng
- Workflow có thông báo, escalation và báo cáo này hoạt động như một hệ thống observability sức khỏe cá nhân, giúp anh không phải một mình chịu trách nhiệm khi đường huyết thấp hoặc có khoảng trống đo lường
Xem đái tháo đường type 1 như một bài toán ứng phó sự cố
- Đái tháo đường type 1 là bệnh tự miễn trong đó tuyến tụy tạo ra rất ít hoặc không tạo ra insulin, chất cần thiết để chuyển carbohydrate thành năng lượng
- Insulin phải được bổ sung bằng cách tiêm, và liều tiêm thay đổi tùy theo thức ăn cùng nhiều biến số khác
- Type 1 không phải là bệnh do lối sống gây ra, và hiện chưa có phương pháp chữa khỏi
- Đường huyết cần được theo dõi liên tục
- Nếu ở mức quá cao trong thời gian dài, có thể dẫn đến tổn thương cơ quan và rút ngắn tuổi thọ
- Nếu ở mức quá thấp, chỉ trong thời gian ngắn cũng có thể gây tử vong
- Khi đường huyết xuống quá thấp, người bệnh có thể không thể ăn hoặc uống một cách an toàn và cần người khác giúp đỡ
- Mỗi khi nhìn thấy đồ ăn hoặc đồ uống, cần tính lượng carbohydrate và lượng insulin cần thiết; ngay cả vận động như đi bộ ngắn cũng phải xét đến lượng insulin còn hoạt động trong cơ thể
- Tình huống mất khả năng nhìn thấy đường huyết có thể được xử lý tương tự trạng thái observability bằng 0 trong hệ thống công việc
- Nếu là công việc, ta sẽ tuyên bố incident và không đóng cho đến khi khôi phục được khả năng quan sát
- Đường huyết thấp là tín hiệu đầu tiên cho thấy có điều gì đó không ổn và cần hành động ngay
Tìm đường đi dữ liệu với Libre, Miao Miao và Tomato
- Thiết bị Libre gắn trên cánh tay có thể đọc đường huyết khi đưa điện thoại lại gần
- Thiết bị cần được thay mỗi 2 tuần
- Khi đường huyết giảm xuống dưới một vạch đỏ nhất định, cần nạp carbohydrate
- Nếu ra khỏi vùng xanh, có thể cân nhắc các biện pháp như tiêm insulin
- Vận động, tăng cân và bệnh tật làm thay đổi độ nhạy insulin, nên quản lý đường huyết luôn là một mục tiêu di động
- Khi Libre báo lỗi, không thể đọc đường huyết từ thiết bị và cũng không thể nhận cảnh báo mức nguy hiểm
- Libre là thiết bị đóng, nên khó lấy dữ liệu trực tiếp nếu không có API hoặc SDK
- Miao Miao được gắn lên trên Libre, quét khoảng mỗi 2 phút và gửi kết quả tới ứng dụng Tomato
- Ngay cả khi ứng dụng Libre mặc định hiển thị lỗi, đường đi qua Miao Miao vẫn tiếp tục phát dữ liệu
- Có vẻ ứng dụng mặc định xem những thay đổi đường huyết đột ngột là ngoại lệ và không gửi dữ liệu; người dùng muốn tự mình đánh giá cả những dữ liệu như vậy
- Ứng dụng Tomato có tính năng phát đường huyết dưới dạng sự kiện Google Calendar mỗi 5 phút, nhờ đó có thể xem đường huyết trên complication của Apple Watch
Xác nhận request của Tomato bằng Go echo server
- Trong phần cài đặt của ứng dụng Tomato có ô nhập URL đồng bộ dữ liệu dành cho Nightscout
- Khi nhập địa chỉ web server tự vận hành thay cho URL Nightscout, đường dẫn sau xuất hiện trong log gateway
/id/e1d67817-4591-4e8e-9bca-58a07a1087d8/api/v1/devicestatus
- Để kiểm tra nội dung request body, anh viết một echo server đơn giản bằng Go
- Việc triển khai và chạy sử dụng encore.dev, cho phép vận hành hệ thống giám sát miễn phí
// 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
}
}
- Echo server là server trả lại nguyên dữ liệu do client gửi, hữu ích cho xử lý sự cố mạng hoặc kiểm thử hành vi ứng dụng
- Dùng cùng cách này để kiểm tra các request khác và nhận được response chứa dữ liệu đường huyết
- date: 1696171541297
sgV: 73
delta: 0
sysTime: 1696171541381
dateString: "2023-10-01T14:45:41.297Z"
_id: "dOUXaI8HcaulCGrQfxe23UE0"
type: "sgv"
device: "Tomato"
direction: "Flat"
sgV là giá trị đường huyết, được chia cho 18 để khớp với đơn vị dùng ở Anh
- Response cũng bao gồm ngày giờ và hướng xu hướng
- Lời gọi này xảy ra mỗi 2 phút
Dashboard Grafana và đồng hồ đo đường huyết
- Giá trị đường huyết nhận được được thiết lập thành Gauge metric
- Gauge là metric biểu diễn một giá trị đơn có thể tăng hoặc giảm, dùng để đo các giá trị biến động như mức sử dụng bộ nhớ, số request đồng thời, nhiệt độ
- Giá trị đường huyết được chuyển đổi bằng
newValue / 18 rồi ghi lại
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)
}
- Dữ liệu đường huyết cũng được lưu vào Postgres theo kiểu best-effort
- Nếu lưu DB thất bại, chỉ ghi log rồi tiếp tục để không làm hỏng phần logic còn lại
- Dashboard Grafana hiển thị theo thời gian thực đồng hồ đo đường huyết được cập nhật mỗi 2 phút
- Khoảng đường huyết mục tiêu lý tưởng là từ 4 đến 9
- Khi chia sẻ dashboard hoặc đặt một màn hình ở nhà, có thể nắm được trạng thái đường huyết trong nháy mắt
Thêm ngữ cảnh đường huyết bằng bot Telegram
- Chỉ số đường huyết thôi là chưa đủ; giống như giám sát hệ thống phức tạp, ngữ cảnh rất quan trọng
- Ngay cả khi đường huyết tăng sau bữa ăn, nếu đã tiêm insulin thì có thể chưa phải là tình huống cần lo ngay
- Grafana hỗ trợ chú thích, nhưng cách phải đăng nhập rồi tự thêm chú thích khá phiền
- Anh tạo bot Telegram và cấu hình để mỗi khi nhận tin nhắn, nó thêm chú thích qua webhook
// 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
}
}
- Webhook nhận request, xác thực tin nhắn, unmarshal JSON rồi trả kết quả xử lý về Telegram
- Sau khi xác thực tin nhắn, nó parse số nguyên và gọi dịch vụ chú thích
- Dịch vụ chú thích gắn tag theo nội dung hoạt động
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"}
}
}
- Trong Grafana có thể chỉ định màu theo tag và thiết lập truy vấn chú thích
- Khi các ngữ cảnh như bữa ăn, vận động, tiêm insulin hiển thị trên đồ thị, bản thân người bệnh và người xem dashboard có thể diễn giải tình hình đường huyết dễ hơn
Chuyển đường huyết thấp thành incident
- Khả năng quan sát đường huyết đã có, nhưng nếu không có cảnh báo thì khó phản ứng theo thời gian thực
- Theo hướng dẫn nhận từ y tá, khi đường huyết xuống dưới 4 thì phải bắt đầu xử trí
- Anh viết một cron nhỏ kiểm tra giá trị đo mỗi 5 phút, và nếu thấp hơn ngưỡng dưới đã định nghĩa trước thì trigger incident
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)
}
}
- Bot Telegram cũng được thêm mã để mở incident thủ công bằng tin nhắn
"i need help"
- Khi incident được trigger, một microservice riêng tạo incident trên incident.io
- Lý do chọn incident.io là vì nó giống nhất với công cụ incident nội bộ của Cloudflare và được viết hoàn toàn bằng 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",
}
- Khi dùng công cụ incident thực sự, có thể thiết lập chính sách escalation và xem các báo cáo như thời gian đã ở trạng thái incident
- Workflow của incident.io có thể cấu hình các quy tắc tương tự Zapier và gửi thông báo SMS cho người đăng ký
- Trong workflow ví dụ, khi incident được mở, nó gửi SMS cho bản thân; nếu chưa đóng sau 20 phút, nó tự động escalation tới bạn đời hoặc anh chị em
Báo cáo và cải tiến trong tương lai
- Dùng công cụ incident cho phép xem bằng báo cáo xem các incident hạ đường huyết đã xảy ra như thế nào theo thời gian
- Đồ thị ví dụ là dữ liệu demo cho blog; dữ liệu thực tế may mắn là nhàm chán hơn nhiều
- Nếu các sự kiện đường huyết thấp có xu hướng tăng, đó có thể là tín hiệu rằng cách điều trị hiện tại không phù hợp và là cơ sở để trao đổi với bác sĩ
- Các hạng mục cải tiến hiện tại hoặc đang lên kế hoạch gồm:
- Tự động đóng: Hiện tại anh đóng incident thủ công để rà soát dữ liệu, nhưng đã có vài lần đóng muộn khiến incident bị escalation, nên có thể tự động đóng nếu đường huyết ổn định khoảng 15 phút
- Trò chuyện với dữ liệu: Anh đang lưu nhiều năm dữ liệu đường huyết, muốn huấn luyện LLM để hỏi các câu như “tại sao cứ 3 giờ chiều lại bị thấp?” và sử dụng kèm các dữ liệu khác như Google Calendar
- Mở rộng đồ thị: Đồ thị hiện còn đơn giản, nhưng có thể thêm các chỉ số như hba1c để đánh giá thành công trong quản lý đái tháo đường
- Tăng cường chống lỗi: Vì hệ thống quan trọng, càng ngăn ngừa được nhiều lỗi càng tốt
Hệ thống vận hành sức khỏe cá nhân được tạo bằng lập trình
- Thời gian đầu sau chẩn đoán type 1, anh từng lo sợ căn bệnh sẽ khiến cuộc sống trở nên khó khăn
- Dự án này giúp anh hiểu, quản lý và giám sát tình trạng type 1
- Anh xử lý quản lý đường huyết như một hệ thống phân tán, biến nó thành một hệ thống vận hành cá nhân có observability, cảnh báo, incident, escalation và báo cáo
- Khả năng lập trình giúp tự động hóa ở một mức độ nhất định việc quản lý một căn bệnh mà đến tận thập niên 1920 vẫn từng được xem là án tử
1 bình luận
Các ý kiến trên Hacker News
Tôi đã sống với bệnh tiểu đường suốt 16 năm, và rất thích cũng như kính trọng tinh thần của tác giả. Khi cảm thấy buồn hay giận vì bệnh, tôi mong tác giả đọc lại bài này và nhớ đến khoảnh khắc hiện tại, khi họ tin chắc rằng mình có thể gánh vác mọi thứ
Không dễ chút nào. Cả về tinh thần lẫn thực tế, và trong trường hợp của tôi, suốt nhiều năm nó gần như là “mất kiểm soát một cách vui vẻ”
Mới hôm qua thôi, lần đầu tiên trong đời sống với tiểu đường, tôi đã thật sự khóc khi thấy mình giữ trong vùng mục tiêu suốt 36 giờ. 100% màu xanh trong 36 giờ. Có lẽ cuối cùng tôi cũng đã hiểu ra
Vài năm sau, chất lượng sống của tôi nhảy vọt lên mức khoảng 60% là nhờ một bộ truyền vi lượng kết nối với CGM, chia sẻ kinh nghiệm với những người tiểu đường khác, cài NightScout VM để có môi trường xem đường huyết và xu hướng ở khắp nơi — điện thoại, đồng hồ, widget desktop, đồng hồ báo thức, tủ lạnh — và nhờ đếm carbohydrate với độ chính xác kiểu Đức, rồi tiêm bolus đúng 15 phút trước bữa ăn. Tôi thật sự ghét phải sống như thế này, nhưng nó có hiệu quả
Hãy trụ vững. Đừng để mình rối loạn
Phong cách viết thật sự hay và đọc rất thú vị. Trùng hợp là tôi làm kiểm thử xâm nhập, và một đồng nghiệp của tôi mắc tiểu đường type 1
Nhìn vào tổng quan trong bài này và những phức tạp đi kèm, tôi càng đồng cảm hơn với người đồng nghiệp ấy — người ngày nào cũng vượt qua những khó khăn đó mà vẫn là một trong những người tử tế và dễ gần nhất trong nhóm
Chỉ là sau khi đọc bài này, tôi mới thật sự cảm nhận được mức độ tự kỷ luật cần có để sống được như vậy
Tất nhiên cũng có thể là công việc kiểu kiểm thử xâm nhập, cố đột nhập vào hệ thống; tôi tò mò không biết bạn đang làm việc đó không
Gần đây tôi đọc một trường hợp về một nhân viên mà ai cũng nghĩ sẽ được thăng chức nhưng cuối cùng lại không. “Tội” duy nhất của người đó là có lần nói ngắn với đồng nghiệp rằng xe bị hỏng và họ mệt vì phải sửa thường xuyên
Vị trí thăng chức sẽ yêu cầu đi làm xa ở mức nào đó, và quản lý được cho là đã nói: “Tôi định thăng chức cho bạn, nhưng tôi nghe nói xe của bạn đang không ổn”
Sau khi Matt trình bày bài này ở GopherConSG, chúng tôi đã nói về vấn đề không thể sở hữu dữ liệu của chính mình. Điều gây ấn tượng với tôi là phía nhà cung cấp dữ liệu, tức các công ty theo dõi đường huyết, phải gánh khá nhiều trách nhiệm pháp lý nên vấn đề khá phức tạp; tôi cũng hiểu vì sao các công ty lớn ngần ngại mở dữ liệu
Mặt khác, việc người dùng không thể truy cập dữ liệu vốn chính đáng là của mình và có thể dùng để hành động trong thực tế thì trông khá bất công
Hôm qua tôi vừa làm một thứ liên quan: một plugin tmux hiển thị dữ liệu đường huyết dưới dạng biểu tượng trạng thái trong terminal
Tôi cũng mắc tiểu đường type 1 và đang dùng Dexcom làm CGM, nên hiện tại tôi đã làm cho nó chạy với môi trường đó, nhưng muốn hỗ trợ thêm thiết bị khác và bổ sung nhiều tính năng hơn. Nếu quan tâm, có thể xem ở đây
https://github.com/Cian911/tmux-xdrip
Ý tưởng Miao Miao khá thú vị. Là người mắc tiểu đường type 1, tôi thấy Freestyle Libre là một thiết bị tuyệt vời thật sự đã thay đổi cuộc đời, nhưng phần mềm thì khá tệ
Tôi đã báo lỗi hơn một năm trước, nhưng Abbott đến giờ vẫn chưa thừa nhận đó là lỗi, dù có rất nhiều báo cáo tương tự trên mạng và trong đánh giá ứng dụng Google Play
Nói thêm cho những ai quan tâm hoặc có thể góp sức để Abbott thừa nhận: đây là lỗi mà dù thêm LibreLink vào danh sách ứng dụng ngoại lệ của chế độ Không làm phiền cũng không có tác dụng; hễ bật chế độ Không làm phiền là lập tức hiện cảnh báo “không thể dùng báo động”. Ở môi trường làm việc, nếu bật Không làm phiền thì cả báo động đường huyết cũng bị tắt, rất bất tiện
Hơi liên quan: 6 tháng trước tôi được chẩn đoán mắc ngưng thở khi ngủ do tắc nghẽn và phải dùng máy CPAP, thiết bị thổi không khí ở áp suất cố định khi ngủ để ngăn đường thở bị tắc. Nó không đến mức tối quan trọng như tiểu đường type 1, nhưng các máy này ghi log nhiều hơn tôi tưởng rất nhiều
Đọc bài này khiến tôi tò mò liệu bên ngưng thở khi ngủ có những cách hack tương tự để theo dõi, hoặc cho các trường hợp nặng hơn, hay không
Tôi đã biết OSCAR và rất biết ơn vì có nó, nhưng cũng tò mò ngoài ra còn có gì nữa
1: https://www.sleepfiles.com/OSCAR/
Trong lần đo giấc ngủ, lúc tệ nhất tôi được ghi nhận có khoảng 48 sự kiện ngừng thở mỗi phút. Khi lưỡi cuộn vào đường thở thì việc hít thở trở nên khá khó khăn
Thú vị đấy, nhưng tôi tự hỏi vì sao tác giả không xem xét các phần mềm mã nguồn mở trong lĩnh vực này như Nightscout, xDrip, v.v.
Đây không phải vấn đề mới, và đã có rất nhiều người giải quyết bằng các giải pháp giàu tính năng hơn nhiều và hoạt động tốt
Scott Hanselman đã viết blog và làm YouTube nhiều năm về tiểu đường type 1 cùng nhiều hack công nghệ. Trước đây ông từng hack để đường huyết hiển thị ngay trong prompt của terminal: https://www.youtube.com/watch?v=_meKUIm9NwA
Những đoạn như “Trong giai đoạn này, thiết bị không thể đo đường huyết, và tôi sẽ không nhận được cảnh báo ngay cả khi đường huyết đạt mức nguy hiểm. Lỗi này có thói quen xuất hiện vào những thời điểm căng thẳng nhất” và “Khi xem xét, có vẻ ứng dụng chính không thích việc gửi dữ liệu khi chỉ số đường huyết thay đổi đột ngột trông giống ngoại lệ” nghe như lỗi đe dọa tính mạng
Nói nghiêm ngặt thì không nên đưa ra quyết định điều trị chỉ dựa trên dữ liệu CGM
Với cảm biến Dexcom, một số ứng dụng có thể lấy giá trị thô và đi vòng qua quá trình này. Với Libre, ít nhất là Libre 3, tôi từng thấy trong một số tình huống nó sẽ điền dữ liệu về sau nếu xác định rằng đó không phải là giá trị đọc sai mà là đường huyết đang thay đổi nhanh
Không dựa trên công nghệ, nhưng cũng có chó cảnh báo tiểu đường
Gần đây tôi được biết rằng những chú chó được huấn luyện tốt đang rất thành công trong việc bổ trợ cho các hệ thống theo dõi/cảnh báo dựa trên công nghệ để báo cho người chăm sóc