- 더운 침실과 체온 민감성 때문에 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_status를standby로 설정함
-
엔드포인트와 응답 구조
- 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_status는active또는standby이며 장치가 온도를 능동적으로 조절하는지를 나타냄
-
온도 값과 장치 제어
- 화씨 온도는 정수, 섭씨 온도는 실수로 다뤄짐
- 정상 범위는 화씨 55~115°F, 섭씨 13.0~48.0°C임
MAX_COLD는-1또는-1.0,MAX_HEAT는999또는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임Device는id,name,attachments를 포함함DeviceStatus는Device.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
- Zig 모듈
- Python 래퍼가 만들어지면 Home Assistant에서 사용하고 싶지만 직접 작성할 계획은 없음
- 동적 라이브러리 빌드와 인터페이스는 아직 준비되지 않았으며 가까운 시점에 추가할 계획임
며칠간 사용한 수면 경험
- 사용한 며칠 동안 주관적으로 푹 잤고, 피트니스 추적기에서도 회복 수면 단계가 길어지고 야간 각성 횟수가 줄어듦
- 위스키를 마신 날에도 평소보다 잘 잤지만 이를 술이 수면에 좋다는 뜻으로 해석해서는 안 됨
- 알코올은 여전히 건강과 수면에 해로우며, 장치가 수면 악화를 일부 줄였을 가능성만 있음
- 장치를 사용한 지 며칠뿐이고
bedctl도 약 3일 밤에 걸쳐 작성했으므로 결과는 아직 허니문 단계임 - 처음 온도를 너무 낮게 설정했을 때는 젖은 곳에 누운 듯한 냉감이 있었지만, 온도를 조정한 뒤 사라짐
- 전환 시간을 직접 측정하지는 않았으나 10분보다는 1분에 가까울 정도로 빠르게 느껴짐
- 채우는 데 필요한 물이 1갤런 미만이라 가열하거나 냉각할 열용량이 크지 않음
리모컨·선풍기·온열 사용
- 기본 리모컨은 터치스크린이 달린 큰 다이얼 형태라 예약 온도를 조율하는 동안 즉시 온도를 바꾸기 쉬움
- 다이얼의 촉감은 만족스럽지 않지만 온도 단위마다 진동해 화면을 보지 않고도 조절할 수 있음
- 수면 마스크를 쓴 상태에서도 햅틱 피드백으로 변경량을 알 수 있음
- 약한 공기 흐름도 필요해 이전에는 방을 식힐 풍량과 몸에 직접 닿거나 기도를 건조하게 하지 않을 세기를 동시에 맞춰야 했음
- Chilipad 사용 후에는 선풍기를 가장 낮은 단계로만 켜도 됨
- 아침에 온도를 약간 높이면 포근하며, 겨울에는 침대를 미리 데우는 기능을 기대함
- 토퍼를 깔면 바닥의 통기성이 다소 줄어듦
- 플라스틱 위에 누운 느낌은 아니지만 높은 온도에서는 침대와 닿은 피부가 아주 약간 땀에 젖는 느낌이 있었음
- 개인적인 체온 조절 특성에 따른 경험이라 다른 사용자에게 동일하지 않을 수 있음
- 초기 경험은 전반적으로 긍정적이며, 동적 라이브러리를 구성한 뒤 후속 내용을 게시할 가능성이 있음