POSA_LEAKSMS/docs
cw2007 2a469dc3cc feat(alert): 누수 감지/복구 디바운스 · 온습도 1시간 주기 · 센서별 수신자 그룹
누수 감지↔복구 플래핑 SMS 폭탄 방지, 온습도 측정 주기 1시간화(부수 오탐
차단), 센서별 SMS 수신자 그룹 지정 3종을 함께 반영한다.

1) 누수 디바운스 (서버 전용, 펌웨어 무변경)
   - leak_sensor_status 에 leak_confirmed / leak_pending_since 컬럼 추가.
   - leak_debounce_decide(): 단일 대칭 타이머 순수 함수. raw 상태가 확인창
     동안 지속돼야 확정하고 확정 엣지에서만 SMS 1회. dry 블립<복구창이면
     복구 미확정 → 확정 유지 → 재감지·복구 SMS 둘 다 차단(폭탄 원천 봉쇄).
   - apply_leak_debounce()/sweep_pending_leak_transitions(): 센서 네임드 락으로
     직렬화, cron sweep 으로 보고 끊겨도 확정 해소. 사고(leak_incident)
     open/close 도 확정 엣지로 이동(월간보고 사고건수 정합). raw 이벤트는
     leak_sensor_log 에 그대로 보존(플래핑 진단).
   - 컬럼 없는 구배포는 레거시 즉시 발송으로 graceful degrade.
   - 확인창 기본: 감지 60s / 복구 180s (config.local.php 조정).

2) 온습도 1시간 주기 + 센서별 히트비트 타임아웃
   - raspberry_pi4_sht30/config.py REPORT_INTERVAL 300→3600.
   - heartbeat_timeout_for(): 명시 오버라이드 > 온습도 기본(7500s) > 전역(1200s).
     cron_heartbeat / dashboard 오프라인 판정을 센서별로. 매시간 오탐 제거,
     누수 오프라인은 20분 유지.
   - STUCK_DETECT_SAMPLES 6→3(1시간 주기 ≈3시간), 관련 주석 정정.

3) 센서별 수신자 그룹
   - SENSOR_RECIPIENTS 맵 + recipients_for_sensor() 전역 폴백.
   - sms_dispatch_to_recipients 가 센서별로 수신자 해소(에스컬레이션 TIER2
     명시 전달은 유지, 헬스/잔액은 전역).

대시보드: 누수 카드 '확인중(디바운스)' 배지, 시스템 탭에 확인창·센서별
타임아웃·수신자 그룹 표시.

마이그레이션: sql/migration_leak_debounce.sql (컬럼 2개), schema_sht30.sql 갱신.
테스트: leak_debounce(12) / recipients_group / heartbeat_timeout 순수 단위 추가.
설계: docs/superpowers/specs/2026-07-13-leak-debounce-sensor-config-design.md
2026-07-13 20:57:17 +09:00
..
assets/security_plan feat: RPi4 누수+온습도 2-모듈 단일 서버 통합 + 보안 하드닝 2026-06-23 16:21:11 +09:00
evidence chore: import codebase with security hardening 2026-06-20 09:37:40 +09:00
examples docs(sht30): 온습도 2번 모듈 문서를 STM32 기본 → Raspberry Pi 기본으로 정합 2026-07-10 10:42:31 +09:00
screenshots feat: RPi4 누수+온습도 2-모듈 단일 서버 통합 + 보안 하드닝 2026-06-23 16:21:11 +09:00
solutions chore: import codebase with security hardening 2026-06-20 09:37:40 +09:00
superpowers feat(alert): 누수 감지/복구 디바운스 · 온습도 1시간 주기 · 센서별 수신자 그룹 2026-07-13 20:57:17 +09:00
build_standalone.py feat: RPi4 누수+온습도 2-모듈 단일 서버 통합 + 보안 하드닝 2026-06-23 16:21:11 +09:00
DEPLOYMENT_PLAN_RPI4x3.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
INSTALL_GUIDE.html docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
INSTALL_GUIDE.standalone.html docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
INSTALL_PI_SERVER.md docs(sht30): 온습도 2번 모듈 문서를 STM32 기본 → Raspberry Pi 기본으로 정합 2026-07-10 10:42:31 +09:00
OPERATIONS_SECURITY_CHECKLIST.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
README.md docs(sht30): 온습도 2번 모듈 문서를 STM32 기본 → Raspberry Pi 기본으로 정합 2026-07-10 10:42:31 +09:00
SECURITY_DOCUMENT_CONSISTENCY_AUDIT.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
SECURITY_EVIDENCE_PACKAGE.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
SECURITY_PLAN_ATTACHMENT_GUIDE.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
SECURITY_PLAN_HWP_REVIEW.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
SECURITY_PLAN_PASS_READINESS.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
SHT30_SENSOR2_SETUP.md docs(sht30): 온습도 2번 모듈 문서를 STM32 기본 → Raspberry Pi 기본으로 정합 2026-07-10 10:42:31 +09:00
SOURCE_SECURITY_EVIDENCE.md docs: 문서 현행화(leak_ 접두사·경로 스크럽) + 코드 투어 + settings deny 수정 2026-07-02 18:52:15 +09:00
stm32f407_migration_plan.md feat: RPi4 누수+온습도 2-모듈 단일 서버 통합 + 보안 하드닝 2026-06-23 16:21:11 +09:00
wiring_diagram.md docs(sht30): 온습도 2번 모듈 문서를 STM32 기본 → Raspberry Pi 기본으로 정합 2026-07-10 10:42:31 +09:00

서버실 온습도(SHT30) 모니터링 시스템 v2606

Sensirion SHT30 온습도 센서를 **Raspberry Pi 4 Model B(Python)**로 I2C 측정하여 Cafe24 PHP/MySQL 서버에 5분 주기로 보고하고, 웹 대시보드 표시와 고온/저온/고습/저습 임계 초과 SMS 알림을 제공하는 시스템입니다. Pi 는 유선 Ethernet(또는 WiFi) + HTTPS(raw-body HMAC 서명)로 보고합니다. (STM32F407VGT6 베어메탈 펌웨어는 별도의 마이그레이션 트랙 firmware/ — 하드웨어 미검증, 현재 배포와 무관.)

구성

[SHT30] --I2C--> [Raspberry Pi 4 (raspberry_pi4_sht30, Python)] --Ethernet/TLS--> [Cafe24 PHP API]
                                                                          |
                                                                      [MySQL DB]
                                                                          |
                                                                [Cafe24 SMS / Dashboard]
  • Raspberry Pi 4 노드 raspberry_pi4_sht30(= deploy/03_pi_b_sht30_id2) — sensor_id=2, device_id=rpi4-sht30-01.
  • SHT30 → Pi I2C 버스 1(GPIO2 SDA / GPIO3 SCL, 주소 0x44, VCC=3.3V/GND, 4.7kΩ 풀업). 상세 배선은 SHT30_SENSOR2_SETUP.md 및 deploy/03_pi_b_sht30_id2/WIRING.html 참조. (STM32 대안 배선 PB6/PB7 은 wiring_diagram.md.)
  • 측정 주기: 5분(raspberry_pi4_sht30/config.py REPORT_INTERVAL=300). 최초 1회 startup, 이후 periodic.
  • 인증: Pi 가 X-Signature = lowercase_hex(HMAC-SHA256(키=API_KEY, 메시지=요청본문 바이트))(raw-body) 헤더로 서명하고 서버가 검증합니다. 관리자 로그인은 비밀번호 해시 + TOTP MFA + 감사로그로 보호합니다.

폴더 구조

docs/
  README.md                 # 설치/운영 허브 문서
  INSTALL_PI_SERVER.md      # Cafe24 서버 설치 설명서 (Pi/STM32 공통)
  OPERATIONS_SECURITY_CHECKLIST.md # 월간 운영·보안 점검표
  SECURITY_EVIDENCE_PACKAGE.md # 보안대책서 첨부자료 패키지
  wiring_diagram.md         # SHT30 I2C 배선도
  SHT30_SENSOR2_SETUP.md    # SHT30 설치 가이드(Raspberry Pi 4 기본 / STM32 마이그레이션 대안)
  solutions/                # 실행-검토 사이클에서 얻은 교훈/반복 방지 기록
firmware/                   # STM32F407VGT6 베어메탈 펌웨어 (sht30_fw)
  common/                   # 이식 코어(sha256/sig/jsonbody/sht30_convert/httpapi/net 등)
  board_sht30/              # SHT30 보드 진입점/측정 태스크
  common/secrets.h.example  # APP_API_KEY 템플릿 (실 secrets.h 는 운영자가 생성, 미커밋)
  certs/                    # 서버 CA (운영 CA 로 교체)
  docs/                     # HARDWARE.md, BUILD_OFFLINE.md, PORTING_NOTES.md
php/
  config.php                # 공통 설정 로더(METRIC_* 임계, HEARTBEAT_TIMEOUT_SEC 등)
  config.local.example.php  # 서버 운영 설정 예시
  ops_checks.php            # 운영 점검 공통 헬퍼
  sms_send.php              # Cafe24 SMS 발송
  cron_heartbeat.php        # 장비 오프라인 감지
  dashboard.php             # 웹 대시보드(현재 온습도/임계 상태)
  setup_wizard.php          # 설치/운영 점검 화면
  security_evidence.php     # 보안대책서 첨부 증적 보고서
  monthly_report.php        # 월간 운영 보고서
  login.php                 # 대시보드 로그인
  setup_mfa.php             # 관리자 TOTP MFA 등록
  admin_security.php        # 관리자 보안/감사 헬퍼
  retention_cleanup.php     # 로그 보관기간 정리
  blocked.php               # 차단 안내 화면
  api/sensor_data.php       # STM32 센서 데이터 수신
sql/
  schema_sht30.sql          # 신규 설치용 통합 스키마 (이 파일 하나로 완결)
_backup/
  pre_v2605_20260519/       # 정리 전 원본 백업

신규 설치 순서

  1. 배선을 확인합니다.

    wiring_diagram.md의 SHT30 I2C 배선(PB6 SCL / PB7 SDA, 주소 0x44, 3.3V/GND, 4.7kΩ 풀업)을 적용합니다.

  2. Cafe24 MySQL에 통합 스키마를 실행합니다.

    SOURCE /path/to/sql/schema_sht30.sql;
    

    phpMyAdmin에서 실행할 때는 sql/schema_sht30.sql 내용을 복사해 실행합니다. 생성 테이블은 leak_sensor_log, leak_sensor_status, leak_sensor_metric, leak_sms_log입니다.

  3. PHP 파일을 업로드합니다.

    public_html/raspi_leck_detecter/
      api/
        sensor_data.php
      var/.gitkeep
      .htaccess
      blocked.php
      config.php
      config.local.php
      ops_checks.php
      sms_send.php
      cron_heartbeat.php
      dashboard.php
      setup_wizard.php
      security_evidence.php
      monthly_report.php
      login.php
      setup_mfa.php
      admin_security.php
      retention_cleanup.php
    
  4. 서버 운영 설정을 만듭니다.

    php/config.local.example.php를 php/config.local.php로 복사한 뒤 실제 DB, API, SMS, 관리자 해시, 관리자 TOTP 값을 입력합니다. 온습도 임계(METRIC_*)를 기관 기준에 맞게 바꾸려면 같은 파일에서 override 합니다(폐쇄망에서 펌웨어 재플래시 불필요).

    관리자 비밀번호 해시는 서버 CLI에서 생성합니다.

    php setup_hash.php "새비밀번호"
    

    최초 관리자 MFA 등록은 MFA_SETUP_TOKEN을 임시로 설정한 뒤 setup_mfa.php?token=임시토큰에서 Google Authenticator 호환 TOTP 키를 생성·검증합니다. 등록 후 화면에 표시되는 ADMIN_TOTP_SECRET을 config.local.php에 반영하고, MFA_SETUP_TOKEN은 빈 값으로 바꾸거나 삭제합니다.

  5. STM32 펌웨어를 빌드·플래시합니다.

    폐쇄망 빌드 머신에서 의존성을 벤더링한 뒤 sht30_fw를 빌드합니다(상세는 firmware/docs/BUILD_OFFLINE.md).

    cp firmware/common/secrets.h.example firmware/common/secrets.h
    # secrets.h 의 APP_API_KEY 를 서버 config.local.php 의 API_KEY 와 동일하게 채운다.
    

    firmware/common/app_config.h의 APP_API_HOST/APP_API_PATH와 네트워크 주소(DHCP/static)를 운영 값으로 설정하고, firmware/certs/server_ca.c의 자리표시자 CA를 실제 Cafe24 루트 CA로 교체합니다.

  6. 서버 cron을 등록합니다.

    장비 오프라인 감지를 위해 cron_heartbeat.php를 1분 간격으로 호출합니다.

    * * * * * php /home/hosting_user/public_html/raspi_leck_detecter/cron_heartbeat.php
    

설치 스키마

신규 설치는 sql/schema_sht30.sql 하나만 실행합니다(누수+온습도 통합, 테이블 전체 leak_ 접두사). 구버전 무접두 테이블 대상 마이그레이션 파일들은 v2607 테이블 리네임과 함께 폐기되었습니다(git 이력 참고).

이벤트 정책

이벤트 조건 DB SMS
startup 기기 시작 첫 측정 leak_sensor_log X
periodic 정상 주기 측정(5분) leak_sensor_metric X
고온/저온/고습/저습 경보 측정값이 임계 초과 leak_sensor_metric.metric_status O (종류별 30분 쿨다운)
정상복귀 경보 후 히스테리시스 포함 정상 회복 leak_sensor_metric O (1회)
장비 오프라인 마지막 수신 후 HEARTBEAT_TIMEOUT_SEC(기본 1200초=20분) 초과 leak_sensor_status O
장비 복구 오프라인 후 재수신 leak_sensor_status O

운영 기준

  • API 키, DB 비밀번호, SMS 인증값, 관리자 해시는 코드에 직접 넣지 않습니다.
  • PHP 서버는 config.local.php 또는 환경 변수에서 운영 값을 읽습니다.
  • STM32 펌웨어는 firmware/common/secrets.h의 APP_API_KEY로 raw-body 서명을 만들며, 이 값은 서버 API_KEY와 같아야 합니다.
  • 온습도 임계는 서버 판정값입니다. 기본값: 고온 30℃ / 저온 10℃ / 고습 70% / 저습 20%, 복귀 히스테리시스 ±1℃·±3%, 동일 종류 쿨다운 1800초(30분). php/config.php의 METRIC_*로 정의하고 config.local.php에서 override 합니다.
  • 임계 경보 SMS는 종류(고온/저온/고습/저습)별로 30분 쿨다운이 적용되어 중복 발송을 막습니다. 정상복귀 SMS는 1회만 발송합니다.
  • 관리자 로그인은 비밀번호 해시 검증 후 TOTP 인증 앱의 6자리 코드를 추가 검증합니다. ADMIN_TOTP_SECRET이 없으면 관리자 로그인을 허용하지 않습니다.
  • 로그인 성공/실패, 로그아웃, MFA 등록 검증은 php/var/admin_audit.log에 감사로그로 기록합니다.
  • heartbeat 체크 실행 주기와 오프라인 판정 시간(HEARTBEAT_TIMEOUT_SEC, 기본 1200초)은 분리되어 있습니다.
  • 대시보드는 위험 상태를 첫 화면에 우선 표시하고, 최신 온습도, 운영 자가진단, 30일 운영 요약을 함께 보여줍니다.
  • 운영 자가진단은 API 키, 관리자 해시, SMS 수신자, 필수 테이블(leak_sensor_metric 포함), 상태 파일 폴더 권한, 최근 SMS 실패를 확인합니다.
  • 월간 보고서는 온습도 임계 경보, 정상복귀, 오프라인/복구, SMS 현황을 조회하고 CSV/인쇄/PDF로 출력할 수 있습니다.
  • 보관기간 정리는 php/retention_cleanup.php --dry-run으로 삭제 대상을 먼저 확인한 뒤, 운영 백업 완료 후 --execute로 수행합니다.
  • 실행-검토 과정에서 나온 실수와 교훈은 docs/solutions/에 남겨 다음 개선 사이클에서 반복하지 않습니다.

운영 화면

화면 경로 용도
대시보드 dashboard.php 현재 온습도, 임계 상태, 센서 상태, 30일 요약
설치 점검 setup_wizard.php DB/설정/권한/SMS 테스트
보안 증적 security_evidence.php 보안통제 매트릭스와 운영 점검 결과
월간 보고서 monthly_report.php 월별 운영 요약, CSV 다운로드, 인쇄/PDF
MFA 등록 setup_mfa.php 관리자 TOTP 인증 앱 등록 및 검증

점검 명령

서버 로그/응답 헤더를 확인합니다.

curl -I https://your-domain.example/raspi_leck_detecter/login.php

STM32 펌웨어는 USART3(PD8/PD9, 115200) 콘솔 로그로 네트워크/SNTP/TLS 핸드셰이크/서버 200 응답을 확인합니다.

서버 보관기간 정리 대상과 백업 증빙을 생성합니다.

php retention_cleanup.php --dry-run
php scripts/backup_evidence.php --backup-dir /path/to/backups --restore-test "YYYY-MM restore OK"

문제 해결

증상 확인 지점
API 403 펌웨어 APP_API_KEY와 서버 API_KEY 일치 여부, raw-body 서명
API 500 Cafe24 PHP 오류 로그, DB 접속 정보, leak_sensor_metric 등 테이블 생성 여부
로그인 불가 config.local.php의 ADMIN_PASSWORD_HASH, ADMIN_TOTP_SECRET, 인증 앱 시간 동기화
SMS 미발송 Cafe24 SMS 인증값, 발신번호 등록, 잔액, leak_sms_log
온습도 미표시 I2C 배선(PB6/PB7, 0x44), 4.7kΩ 풀업, leak_sensor_metric 테이블, 펌웨어 측정 로그
임계 경보 미발송 config.php/config.local.php의 METRIC_* 임계, METRIC_ALERT_COOLDOWN_SEC(30분)
오프라인 알림 지연 HEARTBEAT_CHECK_INTERVAL_SEC, HEARTBEAT_TIMEOUT_SEC(기본 1200초)
대시보드 진단 경고 config.local.php, DB 마이그레이션, php/var 권한