개요

집을 비우면 호두가 뭘 하는지 너무나 궁금했던 아내는 결국 '펫츠뷰'라는 제품을 구매하기에 이르렀다. 이윽고 도착한 제품은 과연 네트워크 지식이 전무한 사람이라도 설치하기가 쉽도록 되어 있긴 했으나 아래와 같은 점이 너무나 거슬렸다.
  • 전용 앱을 통하거나
  • 펫츠뷰 회사 홈페이지를 통해서 보아야 한다
우리 집 거실에 놓인 카메라를 남의 서버를 통하거나 남의 앱을 통해서 본다는게 아무래도 못내 께름칙하거니와, 윈도폰에는 펫츠뷰 앱이 없다는 점도 너무나 안타까울 따름이다.

목표

기본적으로 펫츠뷰 서버를 통하지 않고, 내 폰에서도 볼 수 있도록 해야 한다.

구현방법

카메라 API 확인

펫츠뷰는 국내 회사지만, 카메라 자체는 외제 IP CAM 에다가 자사 연동 기능과 상표만 붙여서 파는 걸로 보였다. IP cam 이므로 카메라의 ip 에 직접 접속해보니 웹 UI 가 존재했다. 중국어의 흔적이 있는 걸로 보아서는 중국 제품인 것 같긴 한데... 여튼 웹 UI 소스를 이리저리 까서 확인한 바로는 여러 회사의 IPCAM 들이 공통적으로 사용하는 CGI API 를 쓰고 있는 점을 알 수 있었다.

서버

집에서 하는 일 별로 없이 노는 라즈베리파이2가 나설 차례다. 요녀석은 사실 미디어서버의 기능도 하고 있지만, 집구석에서 미디어서버 기능을 쓰는 동안은 펫츠뷰를 볼 일이 없으니 부하가 겹치지 않는다는 판단 하에 이놈에게 조금 더 짐을 지우기로 했다. 필요한 기능은 간단한데, 화면을 보여주는 부분과 카메라를 움직이는 부분이다. 사실 IP cam 의 웹 UI 가 있으니까 그걸 그냥 쓰면 되지 않을까 하는 생각도 잠시 했었지만 외부에서 캠으로 바로 접근할 수 있는 경로를 노출하는 건 마음이 께름칙하고, 웹 UI가 딱히 완성도가 높은 것도 아니었기 때문에 인증을 거쳐서 제한된 기능에만 접근 가능하도록 제작하기로 했다. 간단하게 만드는건 역시 node.js 가 편하니까 node.js 에서 http 를 통해 단순한 웹서버로 개발했다.

카메라 화면

이 IP cam 에서는 몇 개의 동영상 스트림을 지원하긴 하는데 하나같이 애매한 놈들 뿐이었다. iOS 기기를 위한 mov 형태의 스트림과 rtsp 프로토콜을 통한 스트림 등이 있었지만 웹에서 바로 보여줄 수는 없었기 때문에 둘 다 OUT. IP CAM 자체적으로 현재 화면을 jpg 이미지로 제공하는 부분이 있어서 해당 이미지를 사용하기로 했다. 고화질과 저화질 이미지가 있는 경로가 /tmpfs/snap.jpg 와 /tmpsf/auto.jpg 로 미묘하게 달라서(아마 이건 펌웨어의 버그인 것 같지만...고칠 수가 없으니 무슨 소용이 있겠는가) 꽤 삽질을 했던 것을 빼면 별다른 어려움은 없었다.

카메라 이동

처음에는 웹 UI 소스를 참조해서 좌우상하 버튼을 누를 때마다 일정 간격으로 이동하도록 했지만 사용해보니 불편하기 짝이 없었다. 그래서 cgi 문서를 확인하고 좌우상하로 이동 시작 => 이동 중단 신호가 올 때까지 계속 이동하도록 구현을 변경하고, 웹페이지에서 버튼 mousedown/touchstart 에서 이동 시작 신호, mouseup/touchend 이벤트에서 이동 중단 신호를 보내도록 변경했다.

인증

그냥 미리 지정한 ID / PW 만 가지고 인증하도록 했다. 각 요청마다 http 헤더나 get 파라미터로 딸려오는 인증 정보를 확인하는 정도에서 끝.

간단하게 html 을 작성하고, jquery 에서 ajax 를 통해 요청을 보낼 때 http 헤더에 인증 정보를 넣도록 beforeSend 핸들러를 간단히 추가했다. 위에서 말한 대로 버튼의 mousedown/mouseup, touchstart/touchend 핸들러를 적절히 코딩하고, 로그인 유지 기능은 localStorage 를 써서 간단하게 붙였다. 쓰고 나니 그냥 다 간단하게 해서 자세히 쓸 내용이 없네..

네트워크

어차피 도메인 갖고 있는게 있으니 서브 도메인을 하나 추가해서 우리집 외부 IP 로 설정했다. 그리고 포트 포워딩을 통해서 특정 포트로 오는 요청을 라즈베리파이로 돌려주면 끝.

결과

  이미지 방식이다보니 소리를 들을 수가 없고, 마이크를 통해 IP cam 에 달린 스피커로 소리를 전송하는 기능도 API 를 찾지 못해서 붙일수가 없었다. 그래도 한나절 붙들고 만든 것 치고는 좋은 결과인듯. (감시의 눈길을 피할 수 없게 된 호두)