1P by GN⁺ | ★ favorite | 댓글 1개
  • 더운 침실과 체온 민감성 때문에 Sleep.me Chilipad 2.0을 1,700달러에 구입하고, 제조사의 클라우드 API를 제어하는 bedctl을 개발함
  • Chilipad는 물이 순환하는 얇은 토퍼와 펌프·저수조·온도조절기를 결합하며, 요일별 온도 예약과 침대 한쪽부터 설치하는 모듈식 구성을 지원함
  • API는 /devices/devices/{:id}에서 기기를 조회하고 PATCH로 온도·작동 상태·화면 밝기·시간대 등을 제어하며, 수위와 현재 수온도 확인할 수 있음
  • Zig으로 작성한 bedctl은 무의존성 라이브러리와 얇은 CLI로 구성되며, 향후 C 인터페이스를 갖춘 libbedctl 동적 라이브러리로 확장할 계획임
  • 초기 수면 추적에서는 회복 수면 시간이 늘고 야간 각성이 줄었지만, 사용 기간이 며칠뿐인 허니문 단계라 장기 효과를 판단하기에는 이름

침대 온도 조절이 필요했던 이유

  • 수면은 면역·인지 기능과 신체 활동 후 회복에 도움이 되지만, 건강 관련 헤드라인에서는 과학적 뉘앙스가 사라질 수 있어 의료진이나 전문가 합의로 뒷받침되는지를 중시함
  • ADHD로 생각이 계속 이어져 잠들기 어려우며, 침대에서 독서하는 습관으로 자극을 줄이고 신경계에 취침 신호를 보내 왔음
  • 자폐 특성으로 특정 질감과 감각에 민감하고 체온 조절도 어려워, 잠들려면 온도와 이불 무게가 적절해야 함
  • Portland의 새 아파트는 에어컨이 거실에만 있고 천장 선풍기도 없어, 고층의 침실이 밤에 가장 더운 공간이 됨
    • 온도 센서를 설치해 침실이 아파트에서 가장 덥다는 점도 확인함
  • 불규칙한 수면, 각성제 복용, 답답한 침실과 체온 민감성이 겹쳐 침대 온도 조절 장치에 비용을 쓰기로 결정함

Chilipad 2.0을 선택한 이유

  • Chilipad 2.0은 물이 든 얇은 매트리스 토퍼를 펌프·저수조·온도조절기가 포함된 장치에 연결해 침대 온도를 제어함
  • 팬으로 공기를 불어 넣는 BedJet은 여름에 차가운 바람이 발에 직접 닿아 제외함
  • Eight Sleep은 가장 저렴한 모델도 3,000달러이고 구독이 필요하며 AI 기능까지 포함돼 구매 대상에서 제외함
  • Chilipad는 침대 한쪽용 장치부터 살 수 있는 모듈식 제품이라 초기 가격이 더 낮음
    • 두 대를 설치하면 양쪽을 서로 다른 온도로 설정할 수 있어 체감 온도가 다른 커플에게 유용함
  • 인터넷 연결 제품이지만 비행기 모드를 지원하고 Bluetooth 리모컨을 기본 제공함
    • 비행기 모드가 Wi-Fi만 끄는지 모든 무선 연결을 차단하는지는 확인하지 않음
    • 처음에는 로컬 API로 잘못 이해했으나 실제로는 클라우드 서비스와 통신함
  • 제조사는 개발자 API, Postman 컬렉션, 온라인 Swagger UI와 OpenAPI 스키마를 제공함

Chilipad 장치 구성

  • Chilipad는 제어 장치인 dock과 물이 순환하는 cover로 구성됨
    • dock에는 온도조절기, 펌프와 저수조가 들어 있음
    • 침대 발치와 방문 가까이에 배치해 열교환기가 내보낸 더운 공기가 침실 안으로 다시 퍼지는 것을 줄임
  • cover는 바닥층, TPU 막으로 만든 hydrolayer, 상단 cover의 세 층으로 구성됨
    • 상단 cover의 지퍼를 열어 사용자가 자는 쪽에 hydrolayer를 설치함
    • 상단에는 만지면 시원한 원단과 얇은 패딩을 사용해 hydrolayer가 직접 느껴지지 않음

Sleep.me API

  • 인증과 Postman 예제

    • API를 사용하려면 먼저 사용자 토큰을 생성해야 하며, 문서는 계정이 있어야 접근할 수 있음
    • Postman 예제는 문서의 세부 정보가 부족할 때 도움이 되지만 별도 회사 계정이 필요하고 구성도 복잡함
    • 오픈소스 hurl 스크립트 같은 대안을 선호함
    • 대부분의 예제에는 변수 이름 오타가 있음
    • {{SleepMeAPI_URL}}이 아니라 대소문자를 구분한 {{SleepMeAPI_Url}}을 사용해야 함
    • “Set Device Status” 예제는 set_temperature_f를 69, thermal_control_statusstandby로 설정함
  • 엔드포인트와 응답 구조

    • API는 기기 목록과 개별 기기를 다루는 두 종류의 엔드포인트를 제공함
    • GET /devices: 토큰에 연결된 기기 목록을 반환함
    • GET /devices/{:id}: 특정 기기의 전체 정보를 반환함
    • PATCH /devices/{:id}: 기기 속성을 변경함
    • /devices의 각 항목에는 기기 ID, 사용자가 정한 이름과 attachments가 포함됨
    • attachments가 연결된 다른 기기를 뜻하는지는 확실하지 않음
    • 상세 응답은 about, control, status 객체로 나뉨
      • about: 펌웨어 버전, 외부 IP, LAN IP, MAC 주소, 모델과 일련번호를 담은 읽기 전용 정보
      • control: 화면 밝기, 표시 온도 단위, 설정 온도, 온도 제어 상태와 시간대 등 변경 가능한 속성
      • status: API 연결 여부, 물 부족 여부, 0~100의 수위와 현재 수온 등 읽기 전용 상태
    • control 속성은 기기별로 다를 수 있으며, 문서에 없는 brightness_level 같은 키가 반환되기도 함
    • thermal_control_statusactive 또는 standby이며 장치가 온도를 능동적으로 조절하는지를 나타냄
  • 온도 값과 장치 제어

    • 화씨 온도는 정수, 섭씨 온도는 실수로 다뤄짐
    • 정상 범위는 화씨 55~115°F, 섭씨 13.0~48.0°C
    • MAX_COLD-1 또는 -1.0, MAX_HEAT999 또는 999.0으로 표현함
    • 대기 상태에서 status.water_temperature_*-1인 것은 센티널 값으로 보이지만 문서화돼 있지 않음
    • 기기 속성을 변경할 때는 바꾸려는 키만 JSON 본문에 넣어 PATCH 요청을 보냄
    • 화씨 온도만 73으로 설정하려면 { "set_temperature_f": 73 }을 전송함
    • 모든 제어 키를 포함하거나 { "control": ... }로 감쌀 필요는 없음
    • 이 요청 방식은 공식 문서가 아니라 Postman 컬렉션을 통해 확인함

bedctl의 구성과 사용법

  • bedctl은 Zig 모듈을 중심으로 만들었으며, CLI는 해당 라이브러리를 호출하는 얇은 래퍼임
  • 이름은 제어 프로그램에 -ctl 접미사를 붙이는 관례를 따르며, “bed cuttle”이 “bed cuddle”처럼 들리는 점도 반영함
  • 주요 명령은 다음과 같음
    • bedctl devices: 토큰에 등록된 기기 이름과 ID 조회
    • bedctl status: 펌웨어, 네트워크 주소, 모델, 설정 온도, 동작 상태, 수위와 관측 온도 조회
    • bedctl set temp 74: 목표 온도 설정
  • 토큰과 기기 ID는 환경 변수로 지정하거나 --token, --device 플래그로 전달할 수 있음

Zig를 선택한 이유와 의존성

  • Rust를 업무에서 약 5년, 취미로 2018년부터 사용했지만 즉각적인 피드백과 낮은 정신적 부담을 원해 최근 선호하는 Zig으로 구현함
  • M1 Max MacBook Pro에서 zig build check --watch -fincremental은 약 75ms에 갱신됨
  • CLI의 유일한 외부 의존성은 TigerBeetle 코드에서 추출·수정하고 Zig 0.16.0에 맞춘 argument parser
  • 라이브러리는 Zig 표준 라이브러리 외에 의존성이 없으며 HTTP 요청에는 std.http.Client를 사용함
  • CLI는 libc와 링크하지 않고, 향후 동적 라이브러리도 libc 없이 구성할 계획임
  • Zig의 기본 교차 컴파일 기능으로 대상 시스템에 직접 접근하지 않고도 지원 플랫폼용 빌드를 만들 수 있음

데이터 모델과 타입 시스템

  • 핵심 구조체는 기기 목록용 Device와 상세 응답용 DeviceStatus
    • Deviceid, name, attachments를 포함함
    • DeviceStatusDevice.About, Device.Control, Device.Status로 구성됨
  • Control 속성은 모델마다 없을 수 있어 밝기, 표시 단위, 설정 온도, 작동 상태와 시간대를 선택형 값으로 표현함
  • JSON 문자열을 그대로 쓰는 대신 Zig의 익명 enum을 활용함
    • 온도 단위는 .c.f
    • 온도 제어 상태는 .active.standby
  • 화씨 설정 온도는 특정 정숫값에 의미 있는 enum 이름을 부여함
    • -1을 기억하는 대신 .max_cold를 사용할 수 있음
    • 일반 온도는 78처럼 정수 리터럴로 전달 가능함
  • 타입만으로 정상 범위인 55~115°F를 제한할 방법은 찾지 못했으며 요청 전 별도 검증도 하지 않음
  • 섭씨 값은 실수여서 허용 범위를 타입으로 표현하지 못함

Zig HTTP 클라이언트 구현 경험

  • Zig 표준 HTTP 클라이언트는 단순한 URI·본문·send 추상화보다 낮은 수준의 절차를 요구함
    • URI 객체 생성
    • 경로를 지정하도록 URI 변경
    • 기본 URI, 헤더와 연결 설정으로 요청 객체 생성
    • 요청 헤드 전송
    • 응답 헤드 수신
    • 본문 reader 생성
    • reader에서 응답 본문 소비
  • 정밀한 제어는 가능하지만, 필요할 때만 저수준으로 내려갈 수 있는 Rust와 달리 Zig에서는 계속 저수준 작업을 하는 느낌이 있음
  • /devices 구현은 인증 헤더를 넣은 GET 요청을 sendBodiless()로 전송한 뒤 응답을 최대 64,000바이트까지 읽어 JSON을 []const Device로 파싱함
  • parseFromSliceLeaky를 사용하지만 외부에 공개하지 않은 arena allocator 구성 덕분에 메모리 해제 문제는 없음

동적 라이브러리 확장 계획

  • 최종 목표는 상위 수준 언어에서 사용할 수 있는 무의존성 동적 라이브러리를 만드는 것임
  • 예정된 구조는 다음과 같음
    • Zig 모듈 bedctl
    • Zig 모듈을 직접 사용하는 CLI bedctl
    • Zig 모듈에 C 인터페이스를 제공하는 libbedctl
    • 동적 라이브러리를 사용하며 C 인터페이스를 자체 검증하는 bedctl-dl
  • Python 래퍼가 만들어지면 Home Assistant에서 사용하고 싶지만 직접 작성할 계획은 없음
  • 동적 라이브러리 빌드와 인터페이스는 아직 준비되지 않았으며 가까운 시점에 추가할 계획임

며칠간 사용한 수면 경험

  • 사용한 며칠 동안 주관적으로 푹 잤고, 피트니스 추적기에서도 회복 수면 단계가 길어지고 야간 각성 횟수가 줄어듦
  • 위스키를 마신 날에도 평소보다 잘 잤지만 이를 술이 수면에 좋다는 뜻으로 해석해서는 안 됨
    • 알코올은 여전히 건강과 수면에 해로우며, 장치가 수면 악화를 일부 줄였을 가능성만 있음
  • 장치를 사용한 지 며칠뿐이고 bedctl도 약 3일 밤에 걸쳐 작성했으므로 결과는 아직 허니문 단계임
  • 처음 온도를 너무 낮게 설정했을 때는 젖은 곳에 누운 듯한 냉감이 있었지만, 온도를 조정한 뒤 사라짐
  • 전환 시간을 직접 측정하지는 않았으나 10분보다는 1분에 가까울 정도로 빠르게 느껴짐
    • 채우는 데 필요한 물이 1갤런 미만이라 가열하거나 냉각할 열용량이 크지 않음

리모컨·선풍기·온열 사용

  • 기본 리모컨은 터치스크린이 달린 큰 다이얼 형태라 예약 온도를 조율하는 동안 즉시 온도를 바꾸기 쉬움
  • 다이얼의 촉감은 만족스럽지 않지만 온도 단위마다 진동해 화면을 보지 않고도 조절할 수 있음
    • 수면 마스크를 쓴 상태에서도 햅틱 피드백으로 변경량을 알 수 있음
  • 약한 공기 흐름도 필요해 이전에는 방을 식힐 풍량과 몸에 직접 닿거나 기도를 건조하게 하지 않을 세기를 동시에 맞춰야 했음
  • Chilipad 사용 후에는 선풍기를 가장 낮은 단계로만 켜도 됨
  • 아침에 온도를 약간 높이면 포근하며, 겨울에는 침대를 미리 데우는 기능을 기대함
  • 토퍼를 깔면 바닥의 통기성이 다소 줄어듦
    • 플라스틱 위에 누운 느낌은 아니지만 높은 온도에서는 침대와 닿은 피부가 아주 약간 땀에 젖는 느낌이 있었음
    • 개인적인 체온 조절 특성에 따른 경험이라 다른 사용자에게 동일하지 않을 수 있음
  • 초기 경험은 전반적으로 긍정적이며, 동적 라이브러리를 구성한 뒤 후속 내용을 게시할 가능성이 있음

댓글과 토론

Lobste.rs 의견들
  • 주제에 맞게 잠들기 직전에 이 글을 올림

    • 특정 시각에 온도를 아주 낮추도록 bedctl을 설정하면 잠을 깨우는 용도로도 쓸 수 있을지 궁금함
  • 제목도 글도 훌륭함. 무게 담요도 써봤는지, 실제로 효과가 있었는지 궁금함

    • 예전에 무게 담요를 썼고 대체로 좋아했지만, 이사하면서 처분했음. 다만 체온 조절에는 도움이 되지 않아 여기서 원하던 해법은 아니었음
      제작 방식에 따라 통기성이 떨어지고 가격도 비쌀 수 있음. Chilipad를 사고 나니 비싸다고 말하기도 민망하지만, 나중에 살펴보려고 기억해 둔 제품은 통기성이 좋아 보이는 개방형 직조 구조의 https://bearaby.com/products/tree-napper
  • 이런 제품을 알아보다가 언젠가는 직접 써볼 생각임. 이 영상에 따르면 가성비 최고의 해법은 양동이지만, 그 경우에는 API가 없을 듯함

    • 그 영상도 봤지만, Home Depot 양동이는 존재하지도 않는 배우자 승인 테스트를 통과하지 못할 것 같음 😅
  • 다소 관련 있는 글: https://trufflesecurity.com/blog/removing-jeff-bezos-from-my-bed (토론)

  • 화씨와 섭씨를 비교한 대목에서 Celsius is the better temperature라고 쓰려던 건 아닌 듯함

  • 글은 재미있고 팬에 관한 부분 등 사고방식에도 많이 공감하지만, 이 작업으로 무엇을 제어할 수 있게 됐는지 명확하지 않음
    물리학 박사 경험 때문에 과학·건강 관련 보도를 입증 전까지 의심한다는 문단은 자칫 백신 불신과 비슷한 위험한 방향으로 읽힘. 다만 박사 과정이 언론의 ‘사실’을 흑백논리로 받아들이지 않게 만들었다는 뜻으로 이해하며, 구체적으로 무엇이 상처를 남겼는지 궁금함

    • 요지는 정반대임. 물리학자라는 이유로 의학에 관한 내 직감까지 특별해지는 것은 아니므로, 기사 몇 편을 읽고 의사 흉내를 내기보다 해당 분야를 연구한 전문가를 따르는 편이 최선임. 권위에 맹목적으로 복종하는 게 아니라 자신의 오류 가능성을 인정하고, 내가 연구한 소수 분야에서도 타인이 내 전문성을 존중해 주길 바라는 태도임
      Andrew Wakefield의 백신 논문이 나왔을 때 초록을 읽은 기자의 짧은 기사만 본 이들이 백신은 절대적으로 위험하다고 단언했고, 동물학 석사인 고등학교 생물 교사와 물리학 박사 세 명까지 백신 반대에 나섰음. 하지만 의료계의 합의는 계속 백신이 안전하고 효과적이며 생명을 구하는 가장 강력한 수단 중 하나라는 것이었고, 만난 의학 연구자들도 모두 일치했음
      박사 과정에서 상처받은 이유는 내 분야의 실제 발견과 뉴스 보도 사이에 얼마나 큰 간극이 있는지 알게 됐기 때문임. 모든 분야를 완전히 이해할 수 없으므로 의학은 의사, 환경은 생태학자, 기후는 기후학자를 신뢰해야 함. 중학교 수준의 수학과 초등학교 수준의 과학으로 전문가를 ‘반박’하는 물리학 박사들을 봤지만, 실제 전문가는 학교 수준의 지식과 현실에 대한 지식 사이의 거대한 차이를 알고 있었음. 내가 공부한 분야에서 그 간극을 목격했기에, 공부하지 않은 분야에서는 오히려 전문가를 더 믿게 됨
  • 원하는 구조로 필드를 아무렇게나 던져도 된다면, 처리기에서 거의 확실히 re.search('set_temperature_f": (\d+)',...) 같은 정규식 검색을 하고 있을 듯함