# 온습도(SHT30) 센서 모듈 — Raspberry Pi 4 Model B 전용 (2번 모듈) **Sensirion SHT30**(한진데이터 P4422-3, I2C) 온습도 센서를 Raspberry Pi 4 Model B 의 I2C 버스로 읽어, 주기적으로 cafe24 서버(`php/api/sensor_data.php`)에 보고하는 모듈입니다. 서버가 측정값을 저장하고, **고온/저온/고습/저습 임계 판정과 SMS, 대시보드 표시**를 모두 수행합니다. > 이 폴더는 STM32F407 펌웨어(`sht30_fw`)의 동작을 **Raspberry Pi 4 + Python 으로 이식**한 > "2번 모듈"입니다. wire 포맷(본문/서명)·CRC·변환식은 펌웨어와 **바이트 단위로 동일**합니다. > "1번 모듈"(누수+카메라)은 `../raspberry_pi4/` 폴더입니다. 전체 구성은 루트의 > [`SYSTEM_OVERVIEW.md`](../SYSTEM_OVERVIEW.md)를 보세요. --- ## 1. 구성 파일 | 파일 | 역할 | |---|---| | `sht30_sensor.py` | 메인 — 주기 측정 → 본문 생성/서명 → POST(재시도), startup→periodic | | `sht30_driver.py` | SHT30 I2C 측정 + CRC-8 검증 + 물리값 변환 (smbus2, 시뮬레이션 폴백) | | `wire.py` | 본문 JSON + raw-body HMAC 서명 (펌웨어 `jsonbody.c`/`sig.c`와 바이트 동일) | | `config.py` | 비밀 아닌 기본 설정(센서 id/주기/범위/ I2C). `config_local` 에서 비밀값 로드 | | `config_local.example.py` | 운영·비밀값 템플릿 → `config_local.py` 로 복사해 사용(미커밋) | | `requirements.txt` | Python 의존성(`requests`, `smbus2`, 핀 고정) | | `install.sh` | Pi 4 설치(폐쇄망 오프라인 + 온라인 폴백, I2C 활성화 포함) | | `vendor.sh` | 폐쇄망용 의존성 사전 다운로드(빌드 머신에서 실행) | | `test_connection.py` | 서버 연결/서명 POST 점검 | | `test_sensor.py` | CRC/포맷 자가점검 + 측정 1회(하드웨어 없이도 포맷 점검 통과) | | `systemd/sht30-sensor.service` | 부팅 자동 실행 서비스 유닛 | --- ## 2. 하드웨어 (Pi 4 Model B 기준) - **Raspberry Pi 4 Model B** (BCM2711) + Raspberry Pi OS **Bookworm 64-bit** - **SHT30** 온습도 센서 모듈 (I2C, 한진데이터 P4422-3) - I2C 풀업 저항 **4.7kΩ × 2** (모듈에 내장된 경우 생략) - 전원: **USB-C 5V/3A**, 네트워크: Pi 4 **Gigabit Ethernet**(유선) 또는 WiFi ### 2.1 핀 배치 (I2C 버스 1) | 신호 | Pi 4 핀 | 비고 | |---|---|---| | SHT30 VCC | 3.3V (물리 1) | **5V 금지** | | SHT30 GND | GND (물리 6/9/14/…) | | | SHT30 SDA | GPIO2 / SDA1 (물리 3) | + 4.7kΩ 풀업 → 3.3V | | SHT30 SCL | GPIO3 / SCL1 (물리 5) | + 4.7kΩ 풀업 → 3.3V | | SHT30 ADDR | GND → 주소 **0x44** | VDD 면 0x45 (`config.py` `I2C_ADDR`) | --- ## 3. 서버 호환성 (반드시 확인) 이 모듈은 **현재 repo 의 `php/` 서버(=cafe24 SHT30 대시보드 서버)**로 보고합니다. 서버는 **raw-body HMAC 서명**을 요구합니다. ``` X-Signature = lowercase_hex( HMAC-SHA256( key=API_KEY, msg=요청본문 바이트 ) ) ``` - `config_local.py` 의 `API_KEY` 는 서버 `config.local.php` 의 `API_KEY` 와 **정확히 동일**해야 합니다. - 서버는 `timestamp` 신선도(±600초)로 재전송을 막으므로 Pi 시각이 **NTP 로 동기**되어 있어야 합니다(Raspberry Pi OS 기본 활성). - `sensor_id=2` 로 보고하며, 서버 대시보드(`dashboard.php`)는 기본 차트로 sensor 2 를 표시합니다. - 임계 경보(고온/저온/고습/저습)·SMS·복구 판정은 **모두 서버**가 수행합니다. 이 모듈은 측정값만 보고합니다. > 서버 측 스키마/배포는 [`../sql/schema_sht30.sql`](../sql/schema_sht30.sql), > [`../docs/INSTALL_PI_SERVER.md`](../docs/INSTALL_PI_SERVER.md), > [`../docs/SHT30_SENSOR2_SETUP.md`](../docs/SHT30_SENSOR2_SETUP.md) 참고. --- ## 4. 설치 ### 4.1 설정값 준비 ```bash cp config_local.example.py config_local.py # config_local.py 를 열어 API_URL / API_KEY / DEVICE_ID / DEVICE_LOCATION 채움 ``` `config_local.py` 가 없으면 실행 시 **명확한 오류로 즉시 중단**됩니다(fail closed). `config_local.py` 와 `API_KEY` 는 **절대 커밋하지 마세요**(`.gitignore` 처리됨). ### 4.2 온라인 설치 (인터넷 가능 환경) ```bash chmod +x install.sh ./install.sh sudo reboot # I2C 를 새로 켠 경우 1회 재부팅 ``` ### 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/ 가 있으면 자동으로 오프라인 설치 ``` > `smbus2` 는 순수 파이썬(arch 무관)이라 x86 빌드 머신에서 받아도 됩니다. > `requests` 등 다른 wheel/deb 는 **aarch64** 용을 받아야 합니다(타깃 arch 에서 `vendor.sh` 권장). --- ## 5. 실행 / 점검 ```bash # 센서가 보이는지 (0x44) i2cdetect -y 1 # 포맷/CRC 자가점검 + 측정 1회 (하드웨어 없으면 시뮬레이션) source venv/bin/activate python3 test_sensor.py # 서버 연결/서명 점검 python3 test_connection.py # 실제 실행 python3 sht30_sensor.py ``` `smbus2` 미설치 또는 I2C 미활성 환경(개발 PC 등)에서는 자동으로 **시뮬레이션 모드**로 동작합니다. --- ## 6. 부팅 자동 실행 (systemd) ```bash # 폴더를 /home/pi/raspberry_pi4_sht30 에 배치했다고 가정 (다르면 .service 의 경로 수정) sudo cp systemd/sht30-sensor.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable sht30-sensor sudo systemctl start sht30-sensor sudo systemctl status sht30-sensor journalctl -u sht30-sensor -f ``` `SupplementaryGroups=i2c` 가 `/dev/i2c-1` 접근에 필요합니다. --- ## 7. 보안 메모 - 비밀값(`API_KEY`)·서버 URL·기기 정보는 `config_local.py`(미커밋)에만 둡니다. 커밋되는 파일에는 placeholder 만 존재합니다. - 보고 본문은 `HMAC-SHA256(API_KEY, raw_body)` 서명(`X-Signature` 헤더)으로 위변조를 방지합니다 (길이확장 공격에 면역). 레거시 body-field sha256 폴백은 서버에서 기본 비활성입니다. - 서명하는 바이트와 전송하는 바이트는 **항상 동일**합니다(`wire.py` 가 본문을 직접 만들어 그 바이트에 서명 후 raw POST). 펌웨어 `sig.c` / `reference.py` / 서버 `verify_signature_raw` 와 바이트 단위로 일치합니다. - `config_local.py` 노출 시 즉시 `API_KEY` 를 교체(서버 동시 변경)하세요.