IoT 코딩도 잘하는 Fable 형님
바이브코딩을 하다 보면 은근히 편견이 하나 생긴다. "이런 AI 모델들은 결국 웹 개발이나 앱 개발처럼 눈에 보이는 분야에서나 잘 하겠지, 하드웨어 특성까지 알아야 하는 임베디드 쪽은 다르지 않을까" 하는 생각이다. 나는 IoT를 업으로 하는 사람이 아니라 그냥 취미로 슬슬 만지는 수준이라, 임베디드 시스템 개발이라는 영역 자체가 나한테도 낯설고 어려운 분야다. 그런데 이번에 ESP32-S3로 Wi-Fi 원격 PC 켜기 프로젝트를 진행하면서, 이 편견이 완전히 깨지는 경험을 했다.
프로젝트는 이거였다. ESP32-S3로 Wake-on-LAN 안 될 때 Wi-Fi 원격 PC 켜기. 신나게 구상하고 코딩을 시작했는데, 진행하면서 세 가지 문제에 부딪혔다.
- USB 전원 관리 탭이 안 생기는 문제 — 이게 없으면 PC가 잠자기 모드에 들어갈 때 USB 디바이스도 같이 죽어버리고, 결국 Wi-Fi도 꺼진다. 원격으로 깨우겠다는 프로젝트의 핵심 전제가 무너지는 셈이다.
- Wi-Fi 불안정 문제 — Wi-Fi를 켤 때 순간적으로 전력이 튀면서 신호를 제대로 못 잡았다.
- 디바이스 인식 안 됨 — 2번 문제 때문에 전력이 부족해져서 USB HID 디바이스로 정상 인식이 안 되는 경우가 잦았다.
이 중에서도 1번이 진짜 고비였다. 이게 안 풀리면 프로젝트 자체가 성립이 안 되는 문제였으니까.
다들 헤매던 문제, Fable 형님은 한 방에
ChatGPT한테 물어봐도 계속 엉뚱한 방향으로 갔고, 제미나이도 마찬가지였다. Claude Opus와 Sonnet으로도 여러 번 시도했는데 안 풀렸다. 그러다 보니 나중엔 "이건 ESP32 디바이스 자체의 물리적 한계다, 더 손볼 게 없다"는 결론까지 내리고 거의 포기하려던 참이었다.
그러다 "형님격"인 Fable한테 한번 물어보고 오자는 생각이 들었다. 그리고 정말 단박에 해결해줬다.
내가 던진 질문은 이거였다. 폴더 안 아두이노 코드를 보여주면서, ESP32-S3로 USB 키보드처럼 동작하는 원격 웨이크업 장치는 만들었는데, 인식된 키보드에 전원 관리 탭이 없어서 원격으로 깨울 수가 없다고. 로지텍 유니파잉이나 중국산 2.4GHz 동글 키보드로는 잘 되는 걸 보면 분명 방법이 있을 텐데, 라고.
Fable은 컴파일까지 확인하고 나서 수정 내용을 이렇게 정리해줬다.
①
USB.usbAttributes(...) 추가 — USB.begin() 직전에 USB 디스크립터에 TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP 비트를 선언하도록 했다. Arduino ESP32 코어 기본값에는 이 비트가 빠져 있어서, Windows가 "이 장치는 깨우기 기능이 없다"고 판단해 전원 관리 탭 자체를 만들어주지 않았던 것. 로지텍 유니파잉 같은 동글은 이 비트를 선언하기 때문에 탭이 생기는 것이었다.②
/wake 핸들러에 tud_suspended() / tud_remote_wakeup() 추가 — PC가 절전 상태일 때는 호스트가 키 입력 자체를 읽어가지 않기 때문에 Keyboard.press()만으로는 소용이 없다. USB 버스에 resume 신호(리모트 웨이크업)를 직접 쏴야 하는데, ESP32 코어가 이걸 자동으로 안 해줘서 명시적으로 호출하도록 고쳤다.여러 모델을 거치며 계속 막혀 있던 문제가 결국 "USB 디스크립터에 깨우기 지원 비트가 빠져 있었다"는 아주 구체적인 하드웨어 레벨의 원인 하나로 정리됐다. 다른 모델들은 계속 코드 표면만 이리저리 바꿔보라고 했지, 이 디스크립터 비트까지 파고든 적이 없었다.
두 번째 고비, 전력 안정화
업로드하고 전원 관리 탭까지 확인했는데, 이번엔 다른 문제가 나왔다. 케이블을 바꿔도 가끔 인식이 잘 안 되는 증상이 계속됐다. 업로드 모드일 때는 멀쩡한 걸 보면 전력 문제 같아서, 좀 더 안정적으로 동작하게 코드를 손볼 수 없겠냐고 다시 물었다.
이번에도 원인을 정확하게 짚어줬다. 가장 결정적이었던 건 setTxPower 호출 위치였다. 원래 코드는 WiFi.begin()보다 먼저 호출하고 있었는데, 이러면 Wi-Fi 드라이버가 아직 시작도 안 한 상태라 이 호출이 조용히 무시된다. 즉 8.5dBm으로 출력을 제한한다고 믿고 있었지만, 실제로는 계속 최대 출력(~20dBm)으로 송신하고 있었던 것. 이 송신 전류 스파이크가 USB 열거 타이밍과 겹치면서 인식이 불안정해지는 근본 원인이었다.
여기에 USB를 Wi-Fi보다 먼저 켜고 tud_mounted()로 열거 완료를 확인한 뒤에야 Wi-Fi를 켜는 순서 조정, CPU 클럭을 240MHz에서 160MHz로 낮추기, Wi-Fi 모뎀 슬립 활성화, /status 진단 엔드포인트 추가(리셋 원인·USB 마운트 상태·RSSI까지 확인 가능)까지 손봐줬다. 덕분에 지금은 꽤 안정적으로 잘 동작한다.
느낀 점
이번 일로 확실히 느낀 건, 임베디드 쪽도 결국 "제대로 아는 모델"에게는 웹 개발이나 별반 다를 게 없는 영역이라는 점이다. USB 디스크립터 비트 하나, setTxPower 호출 순서 하나 같은 건 데이터시트나 스펙 문서를 정확히 이해하고 있어야 짚어낼 수 있는 디테일인데, 다른 모델들이 몇 번을 시도해도 못 찾던 걸 Fable은 한 번에 짚어냈다.
나는 이쪽 분야 전문가가 아니라서 정말 본격적인 임베디드 시스템 개발까지 잘 해낼 수 있을지는 아직 모르겠다. 하지만 이번 기세를 보면, 이 분야도 꽤 잘 해낼 것 같다는 느낌이 든다.
그래서 다음 목표도 하나 생겼다. Windows 11 ARM64용 USB Wi-Fi 드라이버가 없어서 쓰지 못하고 있는 주변기기가 하나 있는데, 이것도 한번 시도해봐야겠다.
'IT > AX' 카테고리의 다른 글
| 바이브코딩 실전 플레이북 (0) | 2026.06.17 |
|---|---|
| [Codex 입문 6/6] Automations·Subagents·Hooks - 안전한 Codex 하네스 (0) | 2026.06.13 |
| [Codex 입문 5/6] Skills·MCP·Plugins - Codex를 내 도구로 확장하기 (0) | 2026.06.13 |
| [Codex 입문 4/6] AGENTS.md와 Memories - Codex가 내 프로젝트를 기억하는 법 (0) | 2026.06.13 |
| [Codex 입문 3/6] Plan과 Goal로 일 맡기기 - 좋은 프롬프트와 검증 (0) | 2026.06.13 |