Home Assistant(이하 HA)를 중심으로 스마트홈을 구축하다 보면, 결국 카메라가 필요해지는 순간이 옵니다. 단순 감시를 넘어 자동화 트리거, 알림, 출입 기록, 그리고 향후에는 이미지 기반 인식까지 확장되기 때문입니다. 문제는 시중 IP 카메라의 선택지가 생각보다 불편하다는 점입니다. 가격이 부담스럽기도 하고, 제조사 앱과 클라우드에 묶여 있거나, 펌웨어 업데이트로 동작이 바뀌는 경우도 종종 있습니다.
그래서 저는 비용이 낮고 구조가 단순한 ESP32-CAM 모듈로 로컬 카메라를 구성해 HA에 직접 붙이는 방법 택했습니다. 완벽한 보안 카메라 대체재라기보다는, 실내 보조용 카메라나 이런 저런 실험을 해보기에 적합합니다. 무엇보다 내부망으로 직접 구축한거라 데이터가 집 밖으로 나가지 않는 구성이 가능하다는 점이 가장 큰 장점입니다.
1. ESP32-CAM은 어떤 보드인가
ESP32-CAM은 Espressif ESP32 칩을 기반으로 한 소형 카메라 보드입니다. Wi Fi, Bluetooth가 기본 탑재되어 있고, OV2640 같은 카메라 센서를 연결해 사진과 영상을 전송할 수 있습니다. 다만 흔히 쓰는 RTSP 카메라처럼 H.264로 인코딩해 스트리밍하는 구조는 아닙니다. ESP32-CAM에는 하드웨어 H.264 인코더가 없기 때문에, 실무적으로는 JPEG 프레임을 연속으로 보내는 MJPEG 스트리밍이 핵심이 됩니다.
MJPEG는 구현이 단순하고 브라우저와 HA에서 바로 소비할 수 있습니다. 반면 프레임마다 JPEG 압축을 반복하기 때문에 대역폭 사용량이 크고, 고해상도와 고프레임을 욕심내면 발열과 메모리 문제가 빠르게 드러납니다. 즉, ESP32-CAM은 "가볍게, 적당한 화질로, 로컬에서" 운용할 때 빛나는 장치입니다.
주요 핀 매핑(OV2640 연결 기준)은 다음과 같습니다.
| 기능 | 핀 | 설명 |
| XCLK | GPIO0 | 외부 클럭 입력 (20 MHz) |
| D0~D7 | GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35 | 영상 데이터 라인 |
| VSYNC | GPIO25 | 프레임 동기 |
| HREF | GPIO23 | 라인 동기 |
| PCLK | GPIO22 | 픽셀 클럭 |
| PWDN | GPIO32 | 전원 제어 |
| LED Flash | GPIO4 | 보드 내장 플래시 LED 제어 |
2. 전체 아키텍처
이번 구성의 핵심은 ESPHome을 이용해 ESP32-CAM을 HA의 네이티브 API로 통합하는 것입니다. 이렇게 하면 HA가 ESP32-CAM을 하나의 장치로 인식하고, 카메라 엔티티뿐 아니라 와이파이 신호, 업타임, 재시작 스위치, 플래시 LED 같은 엔티티까지 함께 다룰 수 있습니다.

3. 준비물과 하드웨어 주의사항
ESP32-CAM은 보드 자체가 저렴한 대신, 초기 업로드 과정에서 실수가 나기 쉬운 편입니다. 특히 전원 품질과 플래싱 절차가 중요합니다.
3.1 준비물
- ESP32-CAM 모듈(가장 흔한 형태는 AI Thinker 계열)
- USB to TTL 시리얼 어댑터(FT232, CP2102 등)
- 점퍼 케이블
- 5V 전원(가능하면 안정적인 어댑터, 전류 여유가 있는 제품)
- 필요 시 외장 안테나(보드가 IPEX 커넥터를 지원하는 모델일 때)
3.2 전원과 발열
카메라 모듈은 프레임 캡처 순간에 전류 피크가 생기고, 와이파이 송신까지 겹치면 순간 전류가 더 튑니다. 이때 전원이 불안정하면 카메라 초기화 실패, 재부팅 루프, 프레임 끊김이 흔하게 발생합니다. 가능하면 USB 포트 전원에만 의존하지 말고, 5V를 안정적으로 공급하세요. 발열도 무시하기 어렵습니다. 지속 스트리밍은 칩을 계속 일하게 만들고, 작은 보드에 열이 모입니다. 실내에서 장시간 운영한다면 프레임레이트를 낮추거나, 필요할 때만 스트리밍되도록 설계를 잡는 편이 안정적입니다.
3.3 플래싱 모드(GPIO0)
ESP32-CAM은 일반 ESP32처럼 GPIO0 상태로 부팅 모드가 결정됩니다. GPIO0를 GND에 붙인 상태로 리셋하면 플래싱 모드로 들어가고, 업로드가 끝나면 GPIO0를 떼고 다시 리셋해 정상 실행 모드로 부팅합니다.
업로드가 자꾸 실패한다면 대부분은 이 GPIO0 상태, 또는 TX RX 연결, 또는 전원 문제로 귀결됩니다.
4. ESPHome과 HA의 관계를 정확히 이해하기
ESPHome을 한 문장으로 요약하면, "ESP 장치를 HA와 자연스럽게 통합해 주는 펌웨어 빌더"입니다. YAML로 장치 구성을 선언하면 ESPHome이 펌웨어를 빌드하고 업로드해 줍니다. 이후 장치는 HA의 ESPHome 통합을 통해 네이티브 API로 연결됩니다.
카메라, 센서, 스위치, 라이트 같은 엔티티가 동일한 장치에서 일관된 방식으로 생성됩니다.
그리고 운영이 쉽습니다. OTA 업데이트는 표준이고, 로그는 대시보드에서 바로 볼 수 있으며, 문제가 생기면 설정만 수정해서 재배포하면 됩니다.
5. ESPHome 설치 방식
HA를 어떤 형태로 운영하느냐에 따라 ESPHome을 올리는 방법이 달라집니다.
5.1 Home Assistant OS, Supervised
이 경우 Add on Store에서 ESPHome을 설치하면 됩니다. 설치 후 Open Web UI로 ESPHome 대시보드에 접속해 새 장치를 만들고 펌웨어를 올리면 됩니다.
5.2 Home Assistant Container, Core
이 경우에는 ESPHome 대시보드를 별도 컨테이너로 띄우는 방식이 일반적입니다. 중요한 건 HA와 같은 네트워크에서 ESP32-CAM을 발견하고, 네이티브 API로 통신할 수 있으면 된다는 점입니다.
6. ESP32-CAM용 YAML 구성
여기서부터는 실전입니다. 아래 예시는 AI Thinker 계열 ESP32-CAM을 기준으로 작성했습니다.
ESPHome의 ESP32 카메라 컴포넌트는 I2C 버스 설정과 PSRAM 설정이 필요합니다. 특히 PSRAM은 최근 버전에서 명시적으로 설정해야 하는 방향으로 바뀌었기 때문에, 카메라를 구성한다면 psram 블록을 넣는 것을 권장합니다.
6.1 예시 설정
esphome:
name: esp32-cam
friendly_name: esp32_cam
esp32:
board: esp32dev
framework:
type: esp-idf
# 최근 ESPHome에서는 PSRAM을 명시적으로 설정하는 구성이 권장됩니다.
psram:
mode: quad
speed: 40MHz
logger:
api:
encryption:
key: !secret esphome_api_encryption_key
ota:
password: !secret esphome_ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "esp32-cam-fallback"
password: !secret esphome_fallback_ap_password
captive_portal:
# I2C 버스를 명시적으로 선언하고, 카메라에 i2c_id로 연결합니다.
i2c:
- id: camera_i2c
sda: GPIO26
scl: GPIO27
esp32_camera:
name: "ESP32 CAM"
external_clock:
pin: GPIO0
frequency: 20MHz
i2c_id: camera_i2c
data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35]
vsync_pin: GPIO25
href_pin: GPIO23
pixel_clock_pin: GPIO22
power_down_pin: GPIO32
resolution: 640x480
jpeg_quality: 12
max_framerate: 10 fps
idle_framerate: 0.1 fps
# 카메라가 PWM 타이머를 점유하므로, LEDC를 쓸 경우 채널을 분리해 주는 것이 안전합니다.
output:
- platform: ledc
channel: 2
pin: GPIO4
id: flash_pwm
light:
- platform: monochromatic
name: "Camera Flash"
output: flash_pwm
sensor:
- platform: wifi_signal
name: "ESP32-CAM WiFi Signal"
update_interval: 60s
- platform: uptime
name: "ESP32-CAM Uptime"
switch:
- platform: restart
name: "ESP32-CAM Restart"
# 로컬 테스트용 웹 서버
# 외부 노출 가능성이 있다면 인증을 꼭 켜는 편이 안전합니다.
web_server:
port: 80
include_internal: true
local: true
auth:
username: !secret esphome_web_username
password: !secret esphome_web_password
6.2 설정 포인트 해설
이 설정에서 안정성과 직결되는 포인트를 짚어보겠습니다.
psram은 카메라 프레임 버퍼에 사실상 필수입니다. PSRAM이 제대로 초기화되지 않으면 부팅 중 카메라 설정 단계에서 실패하거나, 해상도를 올리는 순간 바로 크래시가 납니다.
i2c와 i2c_id는 OV2640 센서 제어를 위한 통로입니다. 연결이 잘못되면 카메라가 초기화되지 않거나, 간헐적으로 검은 화면이 나오는 문제가 생깁니다.
data_pins는 순서가 중요합니다. 단순히 같은 핀을 나열하는 것과 다르게, 카메라 데이터 라인의 매핑 순서가 바뀌면 영상이 깨져 보이거나 아예 나오지 않습니다.
resolution, jpeg_quality, max_framerate는 성능 튜닝의 80퍼센트를 결정합니다. ESP32-CAM의 물리적 한계를 감안하면 VGA(640x480)에서 시작해 안정화하는 것이 좋고, jpeg_quality는 10에서 12 사이가 현장 경험상 균형이 좋습니다.
web_server는 매우 편리하지만 메모리 사용량을 늘립니다. 테스트 단계에서만 켜고, 운영 단계에서는 끄거나 인증을 켜는 편이 안전합니다.
7. 최초 업로드와 OTA 전환
처음 한 번은 시리얼로 올려야 합니다. ESPHome 대시보드에서 Install을 선택하면 업로드 방식을 고를 수 있는데, 초기에는 플러그인 방식 또는 로컬 빌드 방식으로 바이너리를 만든 뒤 시리얼로 업로드합니다.
업로드가 성공하면 이후부터는 OTA로 바뀝니다. 같은 네트워크에 장치가 붙어 있고, OTA 암호가 맞으면 Wirelessly로 바로 업데이트가 됩니다.
로그에서 다음처럼 프레임이 정상적으로 잡히는 메시지가 보이면 카메라가 살아있다고 보면 됩니다.
[I][esp32_camera:205]: Got Image: len=15421
만약 여기까지 왔는데 화면이 자꾸 멈춰 보인다면, idle_framerate와 HA 대시보드의 뷰어 동작을 함께 봐야 합니다. ESPHome 카메라는 "요청이 있을 때만" 적극적으로 프레임을 올리는 방식이라, 스트림을 실제로 열지 않으면 업데이트가 느리게 보일 수 있습니다.
8. Home Assistant 통합 연결
펌웨어 업로드 후 같은 네트워크에 붙어 있으면 HA가 새 ESPHome 장치를 자동으로 발견하는 경우가 많습니다. 자동 발견이 안 되더라도 수동으로 추가하면 됩니다.
설정에서 ESPHome 통합을 추가하고 장치 IP를 입력하면, API 암호화 키를 통해 안전하게 연결됩니다.
연동이 끝나면 일반적으로 다음과 같은 엔티티가 생성됩니다.
| 엔티티 | 설명 |
| camera.esp32_cam | MJPEG 기반 카메라 스트림 |
| light.camera_flash | 플래시 LED 제어 |
| sensor.esp32_cam_wifi_signal | 와이파이 신호 세기 |
| sensor.esp32_cam_uptime | 업타임 |
| switch.esp32_cam_restart | 원격 재시작 |
대시보드에는 그림 카드(Camera Card)를 추가하면 바로 영상이 보입니다. 이때 프레임레이트가 불안정하다면 먼저 ESPHome 로그에서 카메라가 주기적으로 프레임을 보내는지 확인하고, 다음으로는 와이파이 RSSI를 보고 네트워크 상태를 확인하는 순서가 좋습니다.
9. 스트리밍 방식 이해하기: MJPEG의 장단점
ESP32-CAM이 HA로 보내는 스트림은 보통 HTTP 기반 MJPEG입니다. 응답 헤더는 대략 다음 형태를 갖습니다.
Content-Type: multipart/x-mixed-replace; boundary=frame
MJPEG는 프레임이 JPEG 이미지로 이어 붙는 구조라서, 웹 브라우저에서도 쉽게 재생됩니다. 다만 다음 특성이 있습니다.
첫째, 대역폭을 꽤 씁니다. 같은 해상도에서도 H.264보다 트래픽이 커지는 경우가 흔합니다.
둘째, 카메라가 가진 연산 자원이 제한적입니다. 고해상도, 고프레임, 높은 화질을 동시에 만족시키기는 어렵습니다.
셋째, 동시 접속에 약합니다. 여러 클라이언트가 동시에 요청하면 ESP32-CAM이 버티지 못하고 프레임이 깨지거나 리셋되는 경우가 있습니다.
이 특성을 이해하면 설계가 편해집니다. ESP32-CAM은 항상 켜두는 메인 카메라가 아니라, 필요한 순간에 화면을 보고 스냅샷을 활용하는 보조 장치에 가깝습니다.
10. 안정화와 운영 팁
여기부터는 실제로 돌리면서 체감한 내용에 가까운 팁입니다. 작은 차이가 안정성을 크게 바꿉니다.
10.1 해상도와 프레임레이트는 보수적으로 시작하기
처음부터 800x600 이상을 올리면 PSRAM이 있더라도 카메라 초기화 실패가 잦아집니다. VGA에서 시작해 충분히 안정적일 때만 한 단계씩 올리는 편이 좋습니다. 프레임레이트도 10 fps를 기준으로, 발열이나 끊김이 느껴지면 8 fps, 6 fps로 내리면 바로 체감됩니다.
10.2 와이파이 신호가 약하면 모든 것이 불안정해진다
ESP32-CAM은 유선이 없습니다. RSSI가 나쁘면 프레임이 늦고, TCP 재전송이 늘고, 결국 시스템이 불안정해집니다. 설치 위치를 정할 때는 카메라 시야만 보지 말고 AP와의 거리도 함께 보세요. 보드가 외장 안테나를 지원한다면 효과가 확실한 편입니다.
10.3 웹 서버는 테스트용, 운영은 최소 노출
web_server는 디버깅에 아주 좋습니다. 하지만 인증 없이 켜두면 내부망에서 누구나 접근할 수 있는 상태가 됩니다. 실내망이라도 기기 수가 많아지면 공격 표면이 늘어납니다. 운영 단계에서는 web_server를 끄거나, 최소한 auth를 활성화하세요.
10.4 카메라 보드의 특정 핀은 건드리면 안 된다
ESP32-CAM 보드 중 일부는 특정 GPIO가 PSRAM과 묶여 있습니다. 예를 들어 AI Thinker 보드에서는 GPIO16이 PSRAM과 연결되어 있어 다른 용도로 쓰면 워치독 리셋 같은 이상 동작이 발생할 수 있습니다. 카메라가 PSRAM을 쓰는 구성이라면 이 부분은 특히 민감해집니다.
11. HA 자동화 예시: 플래시와 스냅샷을 조합하기
ESP32-CAM 단독으로 모션 감지를 완벽하게 해결하기는 어렵습니다. 대신 HA의 다른 센서와 조합하면 실용성이 올라갑니다. 예를 들어 현관에 PIR 모션 센서가 있고, 그 순간 ESP32-CAM 스냅샷을 찍어서 알림을 보내는 시나리오는 비용 대비 효과가 매우 큽니다.
플래시 LED는 밤에 특히 유용합니다. 주변 조명이 약할 때만 플래시를 켜고, 스냅샷을 찍고, 다시 끄는 식으로 운용하면 발열과 전력도 줄일 수 있습니다.
자동화는 집 구조마다 달라서 여기서는 코드 대신 설계 관점만 말하겠습니다. 핵심은 "영상 스트리밍을 상시로 켜두지 말고, 이벤트 기반으로 활용하라"입니다. ESP32-CAM의 제약이 오히려 이벤트 기반 자동화 설계를 잘 유도합니다.
12. 마무리
ESP32-CAM과 HA를 ESPHome으로 연결하면, 몇 천 원대 부품으로 로컬 카메라를 구성할 수 있습니다. 영상 품질과 스트리밍 안정성만 놓고 보면 상용 IP 카메라를 대체하기는 어렵습니다. 하지만 "로컬 네트워크에서, 자동화와 결합해, 필요한 순간에 쓰는 보조 카메라"라는 관점에서는 꽤 강력한 선택지입니다.
저는 이 구성을 통해 카메라 데이터를 외부로 보내지 않는 스마트홈의 기준을 한 번 더 확실히 잡을 수 있었습니다. 클라우드 의존 없이 더 재미있고 실용적인 자동화를 만들 수 있습니다. 다음 단계로는 모션 센서와 결합한 이벤트 기반 스냅샷 알림, 그리고 필요할 때만 스트림을 열도록 대시보드를 구성하는 쪽으로 확장할 계획입니다.
'IOT > Home Assistant' 카테고리의 다른 글
| Home Assistant 외부 접속 중 untrusted proxy 오류 해결하기 (0) | 2025.11.16 |
|---|---|
| Home Assistant에 Ulanzi Desktop Clock 연동하기 (0) | 2025.10.22 |
| Home Assistant로 구형 에어컨 자동화하기 (2) | 2025.08.17 |
| [Home Assistant] Zigbee2MQTT 2.0.0 업데이트 후 USB 어댑터 인식 오류 해결기 (0) | 2025.04.27 |
| 샤오미 스마트 선풍기 Home Assistant에 추가하기 (0) | 2024.07.01 |