# 누수감지 센서 모듈 — Raspberry Pi 4 Model B 전용 e-con **5C-08 저항형 누수감지센서**를 Raspberry Pi 4 Model B 의 GPIO 로 읽어, 누수 발생 시 즉시 PHP API 서버에 보고(+SMS 발송 트리거)하고 **Pi Camera 로 현장 사진을 촬영해 업로드**하는 모니터링 모듈입니다. > 원래 **Raspberry Pi Zero 2 W** 용으로 작성된 모듈을 **Pi 4 Model B 전용**으로 이식한 > 폴더입니다. GPIO(BCM) 번호 체계와 `rpicam`/`libcamera` 카메라 스택은 두 보드가 동일해 > 센서·촬영 로직은 그대로이며, 차이는 **배선/전원/이더넷/카메라 커넥터**와 설치 환경뿐입니다. --- ## 1. 구성 파일 | 파일 | 역할 | |---|---| | `leak_sensor.py` | 메인 — GPIO 인터럽트 누수 감지, 주기 보고, 누수 시 촬영+업로드 | | `config.py` | 비밀이 아닌 기본 설정(센서/임계/간격/카메라). `config_local` 에서 비밀값 로드 | | `config_local.example.py` | 운영·비밀값 템플릿 → `config_local.py` 로 복사해 사용(미커밋) | | `requirements.txt` | Python 의존성(핀 고정) | | `install.sh` | Pi 4 설치 스크립트(폐쇄망 오프라인 + 온라인 폴백) | | `vendor.sh` | 폐쇄망용 의존성 사전 다운로드(빌드 머신에서 실행) | | `test_connection.py` | 서버 연결/서명 점검 | | `systemd/leak-sensor.service` | 부팅 자동 실행 서비스 유닛 | --- ## 2. 하드웨어 (Pi 4 Model B 기준) - **Raspberry Pi 4 Model B** (BCM2711) + Raspberry Pi OS **Bookworm 64-bit** - e-con **5C-08** 누수감지센서(저항형, 고임피던스 ~1.5MΩ) - **외부 4.7MΩ 풀다운 저항** (필수 — 내부 풀저항은 끔) - (선택) **Pi Camera** — Pi 4 = **15핀(1.0mm 피치) 표준 CSI**, Zero 2 W = **22핀(0.5mm 피치) CSI** → 리본/카메라 보드 호환 안 됨 (Pi 4용 15핀 리본 또는 15↔22 변환 어댑터 필요) - 전원: **USB-C 5V/3A** (카메라 사용 시 여유 전원 권장) - 네트워크: Pi 4 **Gigabit Ethernet**(유선) 또는 WiFi ### 2.1 핀 배치 (기본 센서 1개) | 신호 | BCM | 40핀 헤더 물리 핀 | |---|---|---| | 센서 입력 | GPIO17 | 11 | | 3.3V | — | 1 | | GND | — | 6 (또는 9/14/20/25/30/34/39) | > 센서를 추가하려면 `config.py` 의 `SENSORS` 에 BCM 번호로 항목을 추가합니다. > (예: GPIO27=물리 13번, GPIO22=물리 15번) ### 2.2 전기 설계 (중요) - `ACTIVE_LOW = False`: 건조 시 GPIO=LOW(0), 누수 시 GPIO=HIGH(1) - `USE_INTERNAL_PULL = False`(**PUD_OFF 유지**): 내부 50kΩ 풀다운을 켜면 1.5MΩ 센서가 GPIO 를 HIGH 로 끌어올리지 못해 **감지 실패**합니다. 외부 4.7MΩ 풀다운만 사용하세요. --- ## 3. 서버 호환성 (반드시 확인) 이 모듈은 `leak_alert` / `leak_recovery` 이벤트와 `photo_upload.php` 를 **수신하는 서버**에 보고합니다. > ✅ **이 repo 의 `php/` 서버가 바로 그 서버입니다(단일 서버 통합 완료).** > 1번(누수+카메라)·2번(SHT30 온습도) 두 모듈 모두 **동일한 cafe24 `php/` 서버**에 > raw-body 서명 `X-Signature = lowercase_hex(HMAC-SHA256(key=API_KEY, msg=요청본문 바이트))` > 로 보고하며, 누수 상태·사진·온습도가 하나의 대시보드(`dashboard.php`)에 함께 표시됩니다. > > - **신규 설치:** `sql/schema_sht30.sql` 하나만 실행 — 누수 요소 > (`leak_sensor_log.is_leak` / `leak_sensor_status.is_leak` 컬럼, `leak_incident`, `leak_photo`, > `leak_ingest_nonce` 테이블)가 이미 포함되어 있습니다. > > `config_local.py` 의 `API_URL` / `PHOTO_UPLOAD_URL` 을 이 통합 서버로 설정하고, > `API_KEY` 는 서버 `config.local.php` 의 `API_KEY` 와 **바이트 단위로 동일**하게 맞춥니다. --- ## 4. 설치 ### 4.1 설정값 준비 ```bash cp config_local.example.py config_local.py # config_local.py 를 열어 API_URL / PHOTO_UPLOAD_URL / API_KEY / DEVICE_ID 채움 ``` `config_local.py` 가 없으면 실행 시 **명확한 오류로 즉시 중단**됩니다(fail closed). `config_local.py` 와 `API_KEY` 는 **절대 커밋하지 마세요**(`.gitignore` 처리됨). ### 4.2 온라인 설치 (인터넷 가능 환경) ```bash chmod +x install.sh ./install.sh ``` ### 4.3 폐쇄망(air-gapped) 오프라인 설치 인터넷이 되는 **동일 아키텍처(aarch64, 가급적 동일 Pi 4 + Bookworm 64-bit)** 머신에서 의존성을 먼저 받아 번들을 만든 뒤, 타깃 Pi 4 로 옮겨 설치합니다. ```bash # (빌드 머신, 인터넷 O) wheelhouse/ + debs/ 생성 ./vendor.sh # wheelhouse/ 와 debs/ 를 타깃 Pi 4 의 이 폴더로 복사한 뒤: # (타깃 Pi 4, 인터넷 X) ./install.sh # debs/ · wheelhouse/ 가 있으면 자동으로 오프라인 설치 ``` > `install.sh` 는 `debs/` 가 있으면 `dpkg` 오프라인, `wheelhouse/` 가 있으면 > `pip --no-index` 오프라인으로 설치합니다. 둘 다 없을 때만 인터넷 apt/pip 로 폴백합니다. > wheel/deb 는 아키텍처 종속이므로 x86_64 PC 에서 받은 것은 Pi 4 에서 동작하지 않습니다. --- ## 5. 실행 ```bash source venv/bin/activate python3 leak_sensor.py ``` `RPi.GPIO` 가 없는 환경(개발 PC 등)에서는 자동으로 **시뮬레이션 모드**로 동작합니다. ### 연결 점검 ```bash source venv/bin/activate python3 test_connection.py ``` --- ## 6. 부팅 자동 실행 (systemd) ```bash # 폴더를 /home/pi/raspberry_pi4 에 배치했다고 가정 (다르면 .service 의 경로 수정) sudo cp systemd/leak-sensor.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable leak-sensor sudo systemctl start leak-sensor sudo systemctl status leak-sensor journalctl -u leak-sensor -f ``` `SupplementaryGroups=video` 가 카메라 접근에 필요합니다. --- ## 7. 보안 메모 - 비밀값(`API_KEY`)·서버 URL·기기 정보는 `config_local.py`(미커밋)에만 둡니다. 커밋되는 파일에는 placeholder 만 존재합니다. - 보고 본문은 **raw-body HMAC 서명**으로 위변조를 방지합니다: `X-Signature = lowercase_hex(HMAC-SHA256(key=API_KEY, msg=요청본문 바이트))` (`leak_sensor.sign_raw` ↔ 서버 `config.php::verify_signature_raw`, 2번 모듈과 동일 스킴). - 사진 업로드 서명의 canonical 문자열은 `device_id|sensor_id|log_id|timestamp` (공백 없음)입니다 (`config_local.example.py` 참고). - 구버전의 `sha256(API_KEY + 정렬 JSON)` body-field 서명은 **폐기**되었고, 서버 기본 설정이 거부합니다(`ALLOW_LEGACY_BODY_SIGNATURE=false`, `php/config.php`). - `config_local.py` 노출 시 즉시 `API_KEY` 를 교체(서버 동시 변경)하세요.