POSA_LEAKSMS/docs/superpowers/specs/2026-07-19-node-sensor-integration-design.md
cw2007 90b93f818c chore(deploy+docs): 노드 번들 생성기·하드닝 갱신 + 설계문서
- tools/make_deploy_bundles.py: PMS7003·Zero2W 디스플레이 노드 번들 생성 반영(폐쇄망 동봉)
- tools/harden_pi.sh: 하드닝 스크립트 갱신
- docs/superpowers: 노드 센서 통합·스모크 파일럿·대시보드 다크 설계/계획 문서
- docs/claude-config: IoT 납품·검증 스킬/룰 참조본
- review/: 프로젝트 리뷰·UI v2 목업
2026-07-19 10:48:09 +09:00

6.6 KiB

설계: 누수 노드 다중센서 통합 (누수 + 온습도 + 미세먼지) · 상시 카메라 조명

날짜: 2026-07-19 브랜치: feat/pi-c-sensor3-leak-node 상태: 설계 확정, 구현 진행 대체: 2026-07-18-smoke-node-pilot-design.md (연기 개조/불꽃/CO 경로 폐기) 참조 계획: ../plans/2026-07-18-smoke-node-pilot.md (연기 시범 → PMS7003 metric 통합으로 전환)

목표

기존 누수 노드(Pi-A = sensor_id 1, Pi-C = sensor_id 3)를 한 노드에 3종 센서를 얹은 통합 노드로 확장한다:

  1. 누수 — 기존 leak GPIO(GPIO17, active-high). 변경 없음.
  2. 온습도(SHT30) — I2C metric(metric_type=sht30). 이미 통합됨(2026-07-15 설계).
  3. 미세먼지(PMS7003) — UART metric(metric_type=pms7003). 이번 신규. 연기(화재)의 대리 지표(smoke proxy) — 입자 유입 시 PM 농도가 급등한다.

세 센서 모두 그 노드의 같은 sensor_id(1 또는 3)로 보고하고, metric_type 문자열로만 구분한다. SHT30 동일-id 통합 방식을 그대로 미러(새 id·재번호 없음).

추가로, 누수 확인 카메라(NoIR)용 상시점등 백색 LED를 배선한다(스위칭·코드 없음).

핵심 결정 (확정)

  1. 동일 sensor_id · metric_type 구분. leak_sensor_metric(sensor_id + 측정시각 키)이 온습도·미세먼지를 한 테이블에서 metric_type으로 구분 → 한 sensor_id가 누수 상태 + 온습도 측정 + 미세먼지 측정을 동시에 가진다. PM 행은 pm1_0/pm2_5/pm10만 채우고 temperature_c/humidity_percent는 NULL(반대도 동일) — additive 컬럼.
  2. 노드: 별도 서비스. 불안정한 누수 코드는 건드리지 않는다. PMS7003 는 SHT30 처럼 독립 systemd 서비스(pms7003-sensor)로 얹는다. config 의 SENSOR_ID만 노드별(1/3).
  3. event_type: 첫 성공 판독 = startup, 이후 periodic(SHT30 와 동일). PMS 는 누수/알람 이벤트를 절대 방출하지 않는다 — 임계 판정·SMS 는 전적으로 서버 몫.
  4. Pi metric_status = 물리 타당성만(normal | out_of_range). 서버가 운영 임계를 재평가 하므로 Pi 의 status 를 경보 근거로 신뢰하지 않는다.
  5. 경보/수신자: 전역 METRIC_PM25_HIGH(75)·METRIC_PM10_HIGH(150) 초과 시 서버가 판정 → [미세먼지경보] SMS. 수신자는 기존 sensor_id 1·3 그룹 그대로(추가 매핑 불필요).
  6. 카메라 조명: 상시점등. 스위칭·GPIO 제어 없음. 백색 LED 모듈을 Pi 5V 에 직결해 항상 켠다.

데이터 흐름 / 페이로드

Pi-A (한 대)                                    Pi-C: 동일, sensor_id=3
 ├ leak-sensor.service    → POST(sensor_id=1) leak_alert/recovery/periodic (누수)
 ├ sht30-sensor.service   → POST(sensor_id=1) startup/periodic (metric_type=sht30, 온·습도)
 └ pms7003-sensor.service → POST(sensor_id=1) startup/periodic (metric_type=pms7003, PM)

서버 sensor_data.php: sensor_id=1 metric 저장(metric_type 구분) + 임계 재평가
 → high_pm25/high_pm10 breach → [미세먼지경보] SMS (SENSOR_RECIPIENTS[1])
 → is_leak 보존(비-누수 이벤트는 누수 상태를 덮지 않음)
대시보드: sensor_id=1 → 누수 칩 + 온습도 칩 + 미세먼지 칩

PMS7003 보고 바디 (Pi 가 이 바이트 순서 그대로 만들어 HMAC 서명; KEY 이름 서버와 일치):

{"device_id":"..","device_location":"..","sensor_id":1,"sensor_name":"..","event_type":"periodic",
 "timestamp":<int>,"metric_type":"pms7003","pm1_0":<int>,"pm2_5":<int>,"pm10":<int>,
 "metric_status":"normal","app_version":".."}
  • pm1_0/pm2_5/pm10 = 맨 정수 µg/m³(대기환산), 범위 0..1000.
  • HTTP User-Agent: PMS7003Sensor/2.0 (WAF 우회용 커스텀 UA).

서버 (이미 반영됨 — 참고)

  • 스키마 leak_sensor_metric: pm1_0/pm2_5/pm10 SMALLINT UNSIGNED NULL additive.
  • config.php: METRIC_PM25_HIGH(75) · METRIC_PM10_HIGH(150) · METRIC_PM_HYSTERESIS(10), 쿨다운은 METRIC_ALERT_COOLDOWN_SEC 재사용.
  • 새 breach kind high_pm25 · high_pm10 → 둘 다 SMS_TAG_HIGH_PM = '[미세먼지경보]' 매핑.

하드웨어 배선

PMS7003 (UART, 5V) — TXD 만 읽으면 됨

신호 PMS7003 Pi 4 비고
전원 VCC 5V (물리 pin2) 레이저 팬 구동, 5V 필수
접지 GND GND (물리 pin6)
데이터 TXD RXD = GPIO15 (물리 pin10) PMS → Pi 단방향(읽기)
  • UART 활성화 필수: enable_uart=1 + 직렬 로그인 콘솔 분리(포트 점유 해제). install.sh가 자동 처리, 첫 활성화면 재부팅 필요(migrate.sh 가 안내). 포트 = /dev/serial0.
  • 버스 무충돌: UART(GPIO14/15)는 누수 GPIO17·SHT30 I2C(GPIO2/3)와 겹치지 않는다 → 세 센서 병행 가능.

카메라 조명 (상시점등 백색 LED)

신호 LED 모듈 Pi 4 비고
전원 VCC 5V
접지 GND GND
  • 상시 켜짐 · 스위칭/코드 없음. 저전력 모듈이라 발열 무해, 상시점등해도 문제 없음.
  • NoIR + 백색광 주의: NoIR 카메라 + 백색 LED 는 화면 색이 분홍빛으로 나온다(누수 여부 식별에는 지장 없음). 색을 정상으로 원하면 **일반 카메라(IR-cut 필터 내장)**를 쓴다.
  • 자세한 배선/주의는 raspberry_pi4/WIRING.html "Camera Lighting (Always-On)" 절 참조.

배포 (기존 절차 재사용)

  • 소스 트리: PMS7003 Pi 코드는 raspberry_pi4_pms7003/(SHT30 소스 미러 — pms7003_sensor.py/pms7003_driver.py/install.sh/vendor.sh/systemd/pms7003-sensor.service).
  • 기존 하드닝 노드(SSH off) 대상 USB 원샷 마이그레이션: tools/migration_leak_add_pms7003/ → 생성물 deploy/07_migration_leak_add_pms7003/. migrate.sh가 노드의 기존 config_local.py 에서 API_URL/API_KEY/위치/sensor_id 를 자동 추출해 같은 id 로 통합(시크릿 미포함 번들).
  • 폐쇄망: 빌드 PC 에서 cd pms7003 && bash vendor.sh → debs/·wheelhouse/ 동봉.
  • 서버: config.local.php의 METRIC_SENSOR_IDS 에 1·3 포함 확인(온습도와 동일 목록).

비목표 (YAGNI)

  • Pi-B(sensor_id 2, 온습도 전용) 변경 없음.
  • 연기 개조/불꽃/CO/릴레이 감지 경로 — 전면 폐기(smoke proxy = PM 농도로 대체).
  • PM 기반 자동 카메라 캡처 트리거 — 별개 이슈(이번 범위 밖).
  • 카메라 조명 밝기 제어/스위칭 — 상시점등이라 불필요.