- Vì phòng ngủ nóng và nhạy cảm với thân nhiệt, tác giả đã mua Sleep.me Chilipad 2.0 với giá 1.700 USD và phát triển
bedctlđể điều khiển cloud API của nhà sản xuất - Chilipad kết hợp một tấm topper mỏng có nước tuần hoàn với bơm, bình chứa và bộ điều nhiệt; hỗ trợ đặt lịch nhiệt độ theo ngày trong tuần và cấu hình mô-đun bắt đầu từ một bên giường
- API cho phép truy vấn thiết bị tại
/devicesvà/devices/{:id}, dùngPATCHđể điều khiển nhiệt độ, trạng thái hoạt động, độ sáng màn hình, múi giờ, v.v.; cũng có thể kiểm tra mực nước và nhiệt độ nước hiện tại bedctlviết bằng Zig, gồm thư viện không phụ thuộc và một CLI mỏng; dự định mở rộng thành thư viện độnglibbedctlcó giao diện C trong tương lai- Theo dõi giấc ngủ ban đầu cho thấy thời gian ngủ phục hồi tăng và số lần thức giấc ban đêm giảm, nhưng mới chỉ dùng vài ngày nên vẫn là giai đoạn trăng mật, chưa thể đánh giá hiệu quả dài hạn
Vì sao cần điều chỉnh nhiệt độ giường
- Giấc ngủ giúp ích cho miễn dịch, chức năng nhận thức và phục hồi sau hoạt động thể chất, nhưng các tiêu đề về sức khỏe có thể làm mất sắc thái khoa học, nên tác giả coi trọng việc liệu chúng có được giới y khoa hoặc đồng thuận chuyên gia hậu thuẫn hay không
- Do ADHD, dòng suy nghĩ cứ tiếp diễn khiến khó ngủ; thói quen đọc sách trên giường giúp giảm kích thích và gửi tín hiệu đi ngủ cho hệ thần kinh
- Do đặc điểm tự kỷ, tác giả nhạy cảm với một số kết cấu và cảm giác nhất định, đồng thời khó điều hòa thân nhiệt; để ngủ được thì nhiệt độ và trọng lượng chăn phải phù hợp
- Căn hộ mới ở Portland chỉ có điều hòa trong phòng khách và không có quạt trần, nên phòng ngủ ở tầng cao trở thành nơi nóng nhất về đêm
- Tác giả cũng lắp cảm biến nhiệt độ và xác nhận phòng ngủ là nơi nóng nhất trong căn hộ
- Giấc ngủ thất thường, việc dùng thuốc kích thích, phòng ngủ ngột ngạt và nhạy cảm thân nhiệt cộng lại khiến tác giả quyết định chi tiền cho thiết bị điều chỉnh nhiệt độ giường
Vì sao chọn Chilipad 2.0
- Chilipad 2.0 điều khiển nhiệt độ giường bằng cách nối một topper nệm mỏng chứa nước với thiết bị gồm bơm, bình chứa và bộ điều nhiệt
- BedJet, loại thổi không khí bằng quạt, bị loại vì vào mùa hè luồng gió lạnh thổi trực tiếp vào chân
- Eight Sleep bị loại khỏi danh sách mua vì mẫu rẻ nhất cũng 3.000 USD, cần đăng ký thuê bao và còn kèm cả tính năng AI
- Chilipad là sản phẩm mô-đun, có thể mua thiết bị cho một bên giường trước nên giá ban đầu thấp hơn
- Nếu lắp hai bộ, hai bên có thể đặt nhiệt độ khác nhau, hữu ích cho các cặp đôi có cảm nhận nhiệt khác nhau
- Đây là sản phẩm kết nối Internet nhưng hỗ trợ chế độ máy bay và tặng kèm remote Bluetooth
- Tác giả chưa kiểm tra liệu chế độ máy bay chỉ tắt Wi-Fi hay chặn mọi kết nối không dây
- Ban đầu tác giả hiểu nhầm là API cục bộ, nhưng thực tế thiết bị giao tiếp với dịch vụ đám mây
- Nhà sản xuất cung cấp developer API, bộ sưu tập Postman, Swagger UI trực tuyến và schema OpenAPI
Cấu hình thiết bị Chilipad
- Chilipad gồm dock là bộ điều khiển và cover có nước tuần hoàn
- dock chứa bộ điều nhiệt, bơm và bình chứa
- Tác giả đặt nó ở cuối giường và gần cửa phòng để giảm việc không khí nóng từ bộ trao đổi nhiệt lan ngược vào phòng ngủ
- cover gồm ba lớp: lớp đáy, hydrolayer làm từ màng TPU và cover phía trên
- Mở khóa kéo cover phía trên để lắp hydrolayer vào bên người dùng nằm
- Mặt trên dùng vải mát khi chạm và lớp đệm mỏng, nên không cảm nhận trực tiếp hydrolayer
Sleep.me API
-
Xác thực và ví dụ Postman
- Để dùng API, trước tiên phải tạo token người dùng; tài liệu chỉ truy cập được khi có tài khoản
- Ví dụ Postman hữu ích khi tài liệu thiếu chi tiết, nhưng cần tài khoản công ty riêng và cấu hình cũng phức tạp
- Tác giả thích các lựa chọn thay thế như script
hurlmã nguồn mở hơn - Hầu hết ví dụ có lỗi chính tả ở tên biến
- Phải dùng
{{SleepMeAPI_Url}}có phân biệt chữ hoa/thường, không phải{{SleepMeAPI_URL}} - Ví dụ “Set Device Status” đặt
set_temperature_fthành 69 vàthermal_control_statusthànhstandby
-
Endpoint và cấu trúc phản hồi
- API cung cấp hai loại endpoint: danh sách thiết bị và từng thiết bị riêng lẻ
GET /devices: trả về danh sách thiết bị gắn với tokenGET /devices/{:id}: trả về toàn bộ thông tin của một thiết bị cụ thểPATCH /devices/{:id}: thay đổi thuộc tính thiết bị- Mỗi mục trong
/deviceschứa ID thiết bị, tên do người dùng đặt vàattachments - Không chắc
attachmentscó nghĩa là các thiết bị khác được kết nối hay không - Phản hồi chi tiết được chia thành các object
about,control,statusabout: thông tin chỉ đọc gồm phiên bản firmware, IP bên ngoài, IP LAN, địa chỉ MAC, model và số serialcontrol: các thuộc tính có thể thay đổi như độ sáng màn hình, đơn vị nhiệt độ hiển thị, nhiệt độ đặt, trạng thái điều khiển nhiệt và múi giờstatus: trạng thái chỉ đọc như có kết nối API hay không, có thiếu nước hay không, mực nước từ 0~100 và nhiệt độ nước hiện tại
- Thuộc tính
controlcó thể khác nhau theo thiết bị; đôi khi trả về các khóa không có trong tài liệu nhưbrightness_level thermal_control_statuslàactivehoặcstandby, cho biết thiết bị có đang chủ động điều chỉnh nhiệt độ hay không
-
Giá trị nhiệt độ và điều khiển thiết bị
- Nhiệt độ Fahrenheit được xử lý là số nguyên, nhiệt độ Celsius là số thực
- Khoảng bình thường là 55~115°F theo Fahrenheit, 13.0~48.0°C theo Celsius
MAX_COLDđược biểu diễn bằng-1hoặc-1.0,MAX_HEATbằng999hoặc999.0- Khi ở trạng thái chờ,
status.water_temperature_*bằng-1có vẻ là giá trị sentinel nhưng không được tài liệu hóa - Khi thay đổi thuộc tính thiết bị, chỉ đưa các khóa muốn đổi vào JSON body rồi gửi request
PATCH - Để chỉ đặt nhiệt độ Fahrenheit thành 73, gửi
{ "set_temperature_f": 73 } - Không cần bao gồm mọi khóa điều khiển hoặc bọc bằng
{ "control": ... } - Cách request này được xác nhận qua bộ sưu tập Postman, không phải tài liệu chính thức
Cấu trúc và cách dùng bedctl
bedctlđược xây dựng quanh mô-đun Zig, còn CLI là wrapper mỏng gọi thư viện đó- Tên gọi theo quy ước thêm hậu tố
-ctlcho chương trình điều khiển, đồng thời phản ánh việc “bed cuttle” nghe giống “bed cuddle” - Các lệnh chính như sau
bedctl devices: xem tên và ID thiết bị đã đăng ký với tokenbedctl status: xem firmware, địa chỉ mạng, model, nhiệt độ đặt, trạng thái hoạt động, mực nước và nhiệt độ quan sát đượcbedctl set temp 74: đặt nhiệt độ mục tiêu
- Token và ID thiết bị có thể chỉ định bằng biến môi trường hoặc truyền qua các cờ
--token,--device
Vì sao chọn Zig và các phụ thuộc
- Tác giả dùng Rust khoảng 5 năm trong công việc và từ 2018 cho sở thích cá nhân, nhưng muốn phản hồi tức thì và gánh nặng tinh thần thấp hơn nên triển khai bằng Zig, ngôn ngữ gần đây tác giả ưa thích
- Trên M1 Max MacBook Pro,
zig build check --watch -fincrementalcập nhật trong khoảng 75ms - Phụ thuộc bên ngoài duy nhất của CLI là argument parser, được trích xuất và sửa từ mã TigerBeetle, rồi điều chỉnh cho Zig 0.16.0
- Thư viện không có phụ thuộc nào ngoài thư viện chuẩn Zig và dùng
std.http.Clientcho request HTTP - CLI không liên kết với
libc, và thư viện động trong tương lai cũng dự kiến được cấu hình không cầnlibc - Nhờ khả năng cross-compile mặc định của Zig, có thể tạo bản build cho các nền tảng được hỗ trợ mà không cần truy cập trực tiếp hệ thống đích
Mô hình dữ liệu và hệ thống kiểu
- Các struct cốt lõi là
Devicecho danh sách thiết bị vàDeviceStatuscho phản hồi chi tiếtDevicegồmid,name,attachmentsDeviceStatusgồmDevice.About,Device.Control,Device.Status
- Thuộc tính
Controlcó thể không tồn tại tùy model, nên độ sáng, đơn vị hiển thị, nhiệt độ đặt, trạng thái hoạt động và múi giờ được biểu diễn bằng giá trị tùy chọn - Thay vì dùng nguyên chuỗi JSON, tác giả tận dụng anonymous enum của Zig
- Đơn vị nhiệt độ là
.cvà.f - Trạng thái điều khiển nhiệt là
.activevà.standby
- Đơn vị nhiệt độ là
- Với nhiệt độ đặt theo Fahrenheit, tác giả gán tên enum có ý nghĩa cho một số giá trị nguyên cụ thể
- Có thể dùng
.max_coldthay vì phải nhớ-1 - Nhiệt độ thông thường có thể truyền bằng literal số nguyên như
78
- Có thể dùng
- Tác giả chưa tìm được cách chỉ dùng kiểu để giới hạn khoảng hợp lệ 55~115°F, và cũng không kiểm tra riêng trước khi request
- Giá trị Celsius là số thực nên không thể biểu diễn khoảng cho phép bằng kiểu
Trải nghiệm triển khai HTTP client bằng Zig
- HTTP client chuẩn của Zig yêu cầu quy trình ở mức thấp hơn so với abstraction URI, body và
sendđơn giản- Tạo object URI
- Sửa URI để chỉ định path
- Tạo object request bằng URI cơ sở, header và thiết lập kết nối
- Gửi request head
- Nhận response head
- Tạo reader cho body
- Đọc body phản hồi từ reader
- Có thể kiểm soát chính xác, nhưng khác với Rust, nơi có thể hạ xuống mức thấp khi cần, trong Zig cảm giác như luôn phải làm công việc mức thấp
- Phần triển khai
/devicesgửi requestGETcó header xác thực bằngsendBodiless(), sau đó đọc phản hồi tối đa 64.000 byte và parse JSON thành[]const Device - Dù dùng
parseFromSliceLeaky, nhờ cấu hình arena allocator không phơi ra bên ngoài nên không có vấn đề giải phóng bộ nhớ
Kế hoạch mở rộng thành thư viện động
- Mục tiêu cuối cùng là tạo thư viện động không phụ thuộc dùng được từ các ngôn ngữ cấp cao hơn
- Cấu trúc dự kiến như sau
- Mô-đun Zig
bedctl - CLI
bedctldùng trực tiếp mô-đun Zig libbedctlcung cấp giao diện C cho mô-đun Zigbedctl-dldùng thư viện động và tự kiểm chứng giao diện C
- Mô-đun Zig
- Nếu có wrapper Python, tác giả muốn dùng trong Home Assistant, nhưng không có kế hoạch tự viết
- Bản build thư viện động và giao diện vẫn chưa sẵn sàng, dự kiến sẽ được thêm trong thời gian gần
Trải nghiệm giấc ngủ sau vài ngày sử dụng
- Trong vài ngày sử dụng, tác giả chủ quan cảm thấy ngủ sâu, và thiết bị theo dõi thể lực cũng cho thấy giai đoạn ngủ phục hồi dài hơn, số lần thức giấc ban đêm ít hơn
- Ngay cả hôm uống whisky, tác giả vẫn ngủ ngon hơn bình thường, nhưng không nên diễn giải điều này là rượu tốt cho giấc ngủ
- Rượu vẫn có hại cho sức khỏe và giấc ngủ; chỉ có thể là thiết bị đã phần nào giảm sự suy giảm giấc ngủ
- Thiết bị mới được dùng vài ngày và
bedctlcũng được viết trong khoảng 3 đêm, nên kết quả vẫn còn ở giai đoạn trăng mật - Khi ban đầu đặt nhiệt độ quá thấp, tác giả cảm thấy lạnh như nằm trên chỗ ướt, nhưng cảm giác đó biến mất sau khi điều chỉnh nhiệt độ
- Tác giả không đo trực tiếp thời gian chuyển đổi, nhưng cảm giác nhanh gần 1 phút hơn là 10 phút
- Lượng nước cần đổ vào dưới 1 gallon nên nhiệt dung cần làm nóng hoặc làm lạnh không lớn
Remote, quạt và sử dụng sưởi
- Remote mặc định có dạng núm xoay lớn kèm màn hình cảm ứng, nên dễ đổi nhiệt độ tức thì trong lúc tinh chỉnh nhiệt độ đặt lịch
- Cảm giác xoay núm không thật thỏa mãn, nhưng nó rung theo từng đơn vị nhiệt độ nên có thể điều chỉnh mà không cần nhìn màn hình
- Ngay cả khi đeo mặt nạ ngủ, vẫn biết mức thay đổi nhờ phản hồi xúc giác
- Tác giả cũng cần luồng gió nhẹ, nên trước đây phải vừa chỉnh lưu lượng đủ làm mát phòng, vừa không thổi trực tiếp vào người hoặc làm khô đường thở
- Sau khi dùng Chilipad, chỉ cần bật quạt ở mức thấp nhất
- Tăng nhiệt độ lên một chút vào buổi sáng tạo cảm giác ấm áp dễ chịu, và tác giả mong chờ chức năng làm ấm giường trước vào mùa đông
- Trải topper lên làm giảm phần nào độ thoáng khí của mặt dưới
- Không có cảm giác như nằm trên nhựa, nhưng ở nhiệt độ cao, vùng da tiếp xúc với giường có cảm giác hơi ẩm mồ hôi rất nhẹ
- Đây là trải nghiệm do đặc điểm điều hòa thân nhiệt cá nhân, nên người dùng khác có thể không giống vậy
- Trải nghiệm ban đầu nhìn chung tích cực, và tác giả có thể đăng nội dung tiếp theo sau khi cấu hình xong thư viện động
1 bình luận
Ý kiến trên Lobste.rs
Đăng bài này ngay trước khi đi ngủ đúng với chủ đề
bedctlđể hạ nhiệt độ thật thấp vào một thời điểm nhất định thì có thể dùng nó để đánh thức hay khôngCả tiêu đề lẫn bài viết đều rất hay. Không biết bạn đã thử chăn trọng lực chưa, và nó có thực sự hiệu quả không
Tùy cách làm mà nó có thể kém thoáng khí và cũng khá đắt. Sau khi mua Chilipad thì cũng ngại nói là đắt, nhưng sản phẩm tôi đã ghi nhớ để xem sau là https://bearaby.com/products/tree-napper với kiểu dệt mở có vẻ thoáng khí
Tôi đang tìm hiểu mấy sản phẩm kiểu này và nghĩ rằng rồi sẽ thử dùng một lần. Theo video này, giải pháp đáng tiền nhất là cái xô, nhưng như vậy thì chắc sẽ không có API
Một bài khá liên quan: https://trufflesecurity.com/blog/removing-jeff-bezos-from-my-bed (thảo luận)
Ở đoạn so sánh Fahrenheit và Celsius, có lẽ bạn không định viết Celsius is the better temperature
Bài viết khá vui và tôi cũng rất đồng cảm với cách suy nghĩ của bạn, như phần nói về quạt chẳng hạn, nhưng tôi vẫn chưa rõ chính xác là với công việc này thì bạn đã điều khiển được những gì
Đoạn nói rằng trải nghiệm làm tiến sĩ vật lý khiến bạn nghi ngờ các tin tức về khoa học và sức khỏe cho tới khi được kiểm chứng có thể bị đọc theo hướng khá nguy hiểm, gần giống với tâm lý hoài nghi vaccine. Tuy vậy, tôi hiểu ý là quá trình làm tiến sĩ khiến bạn không còn tiếp nhận các “sự thật” trên báo chí theo kiểu trắng đen, và tôi tò mò không biết cụ thể điều gì đã để lại vết thương như vậy
Khi bài báo về vaccine của Andrew Wakefield xuất hiện, những người chỉ đọc một mẩu tin ngắn của nhà báo sau khi xem phần tóm tắt đã quả quyết rằng vaccine cực kỳ nguy hiểm, và cả giáo viên sinh học trung học có bằng thạc sĩ động vật học lẫn ba tiến sĩ vật lý đều phản đối vaccine. Nhưng đồng thuận của giới y khoa vẫn luôn là vaccine an toàn, hiệu quả và là một trong những công cụ mạnh nhất để cứu người, và tất cả các nhà nghiên cứu y khoa mà tôi từng gặp đều nhất trí như vậy
Điều khiến tôi tổn thương trong quá trình làm tiến sĩ là tôi nhận ra khoảng cách giữa những phát hiện thực sự trong lĩnh vực của mình và cách tin tức đưa tin lớn đến mức nào. Vì không thể hiểu trọn vẹn mọi lĩnh vực, ta nên tin bác sĩ về y học, nhà sinh thái học về môi trường, và nhà khí hậu học về khí hậu. Tôi đã thấy những tiến sĩ vật lý cố “phản biện” chuyên gia bằng toán cấp hai và khoa học cấp một, trong khi chuyên gia thật sự hiểu khoảng cách khổng lồ giữa kiến thức ở trường lớp và kiến thức về thế giới thực. Chính vì đã chứng kiến khoảng cách đó trong lĩnh vực mình học, nên ở những lĩnh vực tôi chưa học, tôi lại càng tin chuyên gia hơn
Nếu cứ có thể ném các trường dữ liệu vào theo bất kỳ cấu trúc nào mình muốn, thì gần như chắc chắn bộ xử lý đang làm kiểu tìm kiếm regex như
re.search('set_temperature_f\": (\\d+)',...)