누수 감지↔복구 플래핑 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
99 lines
5.7 KiB
PHP
99 lines
5.7 KiB
PHP
<?php
|
|
// =============================================================================
|
|
// config.local.example.php - v2606 (SHT30 온습도) 운영 설정 예시
|
|
//
|
|
// 1. 이 파일을 config.local.php로 복사합니다.
|
|
// 2. 실제 운영 값으로 교체합니다.
|
|
// 3. config.local.php는 서버에만 보관하고 공유하지 않습니다.
|
|
// =============================================================================
|
|
|
|
return [
|
|
'DB_HOST' => 'localhost',
|
|
'DB_PORT' => 3306,
|
|
'DB_NAME' => 'your_db_name',
|
|
'DB_USER' => 'your_db_user',
|
|
'DB_PASS' => 'your_db_password',
|
|
|
|
'API_KEY' => 'replace-with-long-random-secret',
|
|
|
|
// 요청 서명은 HMAC-SHA256(키=API_KEY, 메시지=요청본문 바이트)이며 X-Signature 헤더로
|
|
// 전송된다. 레거시 키-접두 sha256 폴백은 기본 비활성이고, 운영(STM32 HMAC 전용)에서는
|
|
// 반드시 false 로 둔다. 과거 RPi(레거시) 클라이언트가 아직 남아 있을 때만 true 로 켠다.
|
|
'ALLOW_LEGACY_BODY_SIGNATURE' => false,
|
|
|
|
'SMS_USER_ID' => 'your-cafe24-sms-user-id',
|
|
'SMS_SECURE' => 'your-cafe24-sms-secure-key',
|
|
'SMS_SENDER' => '01000000000',
|
|
'SMS_RECIPIENTS' => [
|
|
'01000000000',
|
|
],
|
|
|
|
// 센서별 수신자 그룹 — 지정한 센서의 경보 SMS 는 그 그룹으로만 발송된다. 지정 없는
|
|
// 센서는 위 전역 SMS_RECIPIENTS 로 폴백한다(헬스/잔액 등 시스템 통지도 전역 사용).
|
|
// 예: 누수(1번)는 시설팀, 3번은 고객센터로. 비우면(기본) 전역만 사용.
|
|
'SENSOR_RECIPIENTS' => [
|
|
// 1 => ['010-1111-1111', '010-2222-2222'],
|
|
// 3 => ['010-3333-3333'],
|
|
],
|
|
|
|
'ADMIN_USER' => 'admin',
|
|
'ADMIN_PASSWORD_HASH' => '$2y$10$replace.with.password_hash.output',
|
|
// Base32 TOTP secret. MUST be left EMPTY here and set to a UNIQUE generated value in
|
|
// config.local.php. Empty '' => admin_mfa_configured() is false => login is DISABLED
|
|
// (fail-closed) until a real secret is set. NEVER put a literal Base32 string in this
|
|
// example file: any non-empty Base32-ish value (even "REPLACE_WITH_...") decodes to a
|
|
// usable, publicly-known TOTP secret and silently enables MFA on a known seed.
|
|
// Generate a unique secret on the server only:
|
|
// php -r "require 'php/admin_security.php'; echo admin_totp_secret().PHP_EOL;"
|
|
'ADMIN_TOTP_SECRET' => '',
|
|
// Temporary bootstrap token for setup_mfa.php. Remove or empty after MFA enrollment.
|
|
'MFA_SETUP_TOKEN' => 'replace-with-temporary-random-token',
|
|
|
|
// 누수 모듈 sensor_id 목록 — 대시보드 누수 상태 카드 표시 대상 (기본 [1]).
|
|
// 신규 누수 지점(예: Pi-C, sensor_id 3) 투입 시: [1, 3]
|
|
'LEAK_SENSOR_IDS' => [1],
|
|
|
|
// 누수 감지/복구 디바운스(감지↔복구 플래핑 SMS 폭탄 방지). 상태가 확인창 동안 지속돼야
|
|
// 확정하고 확정 엣지에서만 SMS 1회. 아래는 기본값(필요 시 조정). sql/migration_leak_debounce.sql
|
|
// 적용 필요(컬럼 없으면 레거시 즉시 발송으로 자동 폴백).
|
|
// 'LEAK_DEBOUNCE_ENABLED' => true,
|
|
// 'LEAK_ALERT_CONFIRM_SEC' => 60, // 감지 확인창(초)
|
|
// 'LEAK_RECOVERY_CONFIRM_SEC' => 180, // 복구 확인창(초)
|
|
|
|
// 센서별 오프라인 판정 타임아웃(무수신 초). 온습도(SHT30)는 1시간 주기라 전역 20분으론
|
|
// 매시간 오탐 → 온습도 센서는 METRIC_HEARTBEAT_TIMEOUT_SEC(기본 7500s≈125분) 자동 적용.
|
|
// 특정 센서만 다르게 하려면 SENSOR_HEARTBEAT_TIMEOUT_SEC 로 명시 오버라이드.
|
|
// 'METRIC_HEARTBEAT_TIMEOUT_SEC' => 7500,
|
|
// 'SENSOR_HEARTBEAT_TIMEOUT_SEC' => [3 => 1800],
|
|
|
|
// 온습도 임계 경보 (서버 판정 → SMS). 운영 환경에 맞게 조정.
|
|
'METRIC_TEMP_HIGH_C' => 27, // 고온 임계(℃)
|
|
'METRIC_TEMP_LOW_C' => 10, // 저온 임계(℃)
|
|
'METRIC_RH_HIGH' => 60, // 고습 임계(%)
|
|
'METRIC_RH_LOW' => -1, // 저습 경보 비활성(RH 는 항상 ≥0 → 절대 발화 안 함)
|
|
'METRIC_DEWPOINT_MARGIN_C' => 0, // 결로(이슬점) 경보 비활성(0 이면 판정 분기 스킵)
|
|
'METRIC_ALERT_COOLDOWN_SEC' => 1800, // 동일 종류 경보 재발송 억제(초, 기본 30분)
|
|
|
|
// 예보·대응(대시보드 예방 신호 + 조치 가이드). 전부 기본값으로 동작 — 필요 시만 override.
|
|
// FORECAST_ENABLED(true), FORECAST_WARN_MARGIN_TEMP_C(2.0), FORECAST_WARN_MARGIN_RH(8.0),
|
|
// FORECAST_HORIZON_MIN(180), FORECAST_RATE_TEMP_C_PER_10MIN(3.0) 등. config.php 참고.
|
|
// 대응 담당자(대시보드 '대응 필요' 섹션에 표시). 비우면 담당자 블록 생략.
|
|
'RESPONSE_CONTACTS' => [
|
|
// ['role' => '시설담당', 'name' => '홍길동', 'phone' => '010-0000-0000'],
|
|
// ['role' => '야간당직', 'name' => '김철수', 'phone' => '010-0000-0000'],
|
|
],
|
|
// 상태별 대응 체크리스트는 config.php 의 기본 플레이북을 사용. 현장 절차로 바꾸려면
|
|
// 'RESPONSE_PLAYBOOKS' => ['high_temp' => ['title'=>'고온 대응','steps'=>['...']], ...] 로 통째 override.
|
|
|
|
// 미복귀 경보 2차(야간) 에스컬레이션 수신자. 비우면 비활성(opt-in).
|
|
'SMS_RECIPIENTS_TIER2' => [],
|
|
'ESCALATE_AFTER_SEC' => 1800, // 경보 미복귀 30분 후 2차 통지
|
|
// 아래는 기본값으로 동작(필요 시에만 override):
|
|
// SMS_BALANCE_WARN_THRESHOLD(30건), HEALTH_SMS_HOUR(9시),
|
|
// STUCK_DETECT_SAMPLES(3 = 온습도 1시간 주기 기준 ≈3시간), SMS_RETRY_OFFLINE(true)
|
|
|
|
'SMS_LOG_RETENTION_DAYS' => 365,
|
|
'SENSOR_LOG_RETENTION_DAYS' => 365,
|
|
'SENSOR_METRIC_RETENTION_DAYS' => 365,
|
|
'ADMIN_AUDIT_RETENTION_DAYS' => 365,
|
|
];
|