$s) { $sensor_cards[(int)$sid] = ['metric' => true, 'leak' => false, 's' => $s]; } foreach ($leak_statuses as $sid => $s) { $sid = (int)$sid; if (isset($sensor_cards[$sid])) { $sensor_cards[$sid]['leak'] = true; if ($sensor_cards[$sid]['s'] === null) { $sensor_cards[$sid]['s'] = $s; } } else { $sensor_cards[$sid] = ['metric' => false, 'leak' => true, 's' => $s]; } } ksort($sensor_cards); ?>
실시간 상태 Live

센서 현황 · 개소

$card): $is_metric = $card['metric']; $is_leak_node = $card['leak']; $s = $card['s']; // 보고 주기 표기 — 누수 노드(결합)는 10분, 온습도 단독은 1시간 // (config.php heartbeat 주석 기준: raspberry_pi4 REPORT_INTERVAL=600 / sht30=3600) $cycle_label = $is_leak_node ? '10분 주기' : '1시간 주기'; // 미세먼지 노드 여부(PM_SENSOR_IDS) — 온습도·누수와 독립적으로 카드에 PM 계통 표시. $is_pm_node = in_array((int)$sid, array_map('intval', PM_SENSOR_IDS), true); $type_labels = []; if ($is_leak_node) { $type_labels[] = ['leak', '누수']; } if ($is_pm_node) { $type_labels[] = ['pm', '화재감시']; } if ($is_metric) { $type_labels[] = ['metric', '온습도']; } // ── 미수신 placeholder ── if ($s === null): ?>
번 센서
데이터 없음
아직 수신된 데이터가 없습니다.
수신 대기
누수 확정 > 확인중(디바운스) > 미세먼지 경보 > 온습도 경보 > 정상 ── $metric_code = $s['metric_status'] ?? 'normal'; $pm_code = $s['pm_status'] ?? 'normal'; $has_m_alert = $is_metric && !empty($s['is_alerting']); $has_pm_alert = $is_pm_node && !empty($s['is_pm_alerting']); $is_leaking = $is_leak_node && (int)($s['leak_confirmed'] ?? $s['is_leak'] ?? 0) === 1; $is_pending = $is_leak_node && !empty($s['leak_pending']); if ($s['is_offline']) { $card_class = 'offline'; $line_class = 'off'; $line_text = '오프라인'; if ($is_leaking) { $line_text .= ' (누수 중 끊김)'; } elseif ($has_pm_alert) { $line_text .= ' (' . metric_status_label($pm_code) . ' 중 끊김)'; } elseif ($has_m_alert) { $line_text .= ' (' . metric_status_label($metric_code) . ' 중 끊김)'; } } elseif ($is_leaking) { $card_class = 'leak'; $line_class = 'leakst'; $line_text = '누수 감지'; } elseif ($is_pending) { $card_class = 'pending'; $line_class = 'pend'; $line_text = '확인중(디바운스)'; } elseif ($has_pm_alert) { $card_class = 'pm'; $line_class = 'pmst'; $line_text = metric_status_label($pm_code) . ' 경보'; } elseif ($has_m_alert) { $card_class = 'alert'; $line_class = 'err'; $line_text = metric_status_label($metric_code) . ' 경보'; } else { $card_class = ''; $line_class = 'ok'; $line_text = $is_leak_node ? '정상 (건조)' : '정상'; } ?>
/
경과 분 SMS 건 감지 확정 — 현장 확인 필요
°C
온도
%
습도
= 2): $sp_series = []; foreach (['temp' => 'sp-t', 'hum' => 'sp-h'] as $sp_key => $sp_cls) { $sp_vals = array_map(fn($p) => $p[$sp_key], $sp); $sp_nums = array_filter($sp_vals, fn($v) => $v !== null); if (count($sp_nums) < 2) { continue; } $sp_min = min($sp_nums); $sp_max = max($sp_nums); $sp_rng = ($sp_max - $sp_min) ?: 1; $sp_pts = []; foreach ($sp_vals as $sp_i => $sp_v) { if ($sp_v === null) { continue; } $sp_x = $sp_n > 1 ? $sp_i * (300 / ($sp_n - 1)) : 150; $sp_y = 3 + (1 - ($sp_v - $sp_min) / $sp_rng) * 28; $sp_pts[] = sprintf('%.1f,%.1f', $sp_x, $sp_y); } if (count($sp_pts) >= 2) { $sp_series[$sp_cls] = implode(' ', $sp_pts); } } if (!empty($sp_series)): ?> $sp_points): ?>
측정값 없음
µg/m³
PM2.5
µg/m³
PM10
화재감시(PM) 측정값 없음
near>safe) ── if ($is_metric): $fc = (!$s['is_offline'] && isset($forecasts[$sid])) ? $forecasts[$sid] : null; if ($fc): $chips = []; foreach ($fc['headroom'] as $h) { $chips[] = ['state' => $h['state'], 'text' => $h['label'] . ' 여유 ' . $h['margin'] . $h['unit']]; } foreach (['temp', 'hum'] as $vk) { $e = $fc['trend'][$vk]['eta'] ?? null; if ($e) { $chips[] = ['state' => 'near', 'text' => '↗ ~' . (int)$e['min'] . '분 뒤 ' . metric_status_label($e['key'])]; } } foreach ($fc['rate'] as $r) { $chips[] = ['state' => 'near', 'text' => ($r['spike'] === 'rise' ? '급상승 ' : '급락 ') . ($r['per10'] > 0 ? '+' : '') . $r['per10'] . '/10분']; } if (!empty($fc['dew']['risk'])) { $chips[] = ['state' => 'near', 'text' => '결로주의 (마진 ' . $fc['dew']['margin'] . '℃)']; } $chip_rank = ['over' => 0, 'near' => 1, 'safe' => 2]; usort($chips, fn($a, $b) => ($chip_rank[$a['state']] ?? 3) <=> ($chip_rank[$b['state']] ?? 3)); ?>
예보: 임계 여유 충분
최종확인 (분 전)

아직 수신된 센서 데이터가 없습니다.

미복구 누수 사고 · 건

#센서위치감지 시각상태
미복구

사진·복구 시각 등 전체 사고 이력은 이력 조회 탭에서 확인하세요.

채널·오늘 요약

SMS 채널 상태

잔여 건수
마지막 성공 발송
오늘 발송 / 실패
건 / 건

SMS는 유일한 경보 채널입니다. 잔여 건수가 건 이하면 충전하세요.

오늘 경보 요약

오늘 경보 횟수
건
오늘 최근 경보
가동률
% (/ 온라인)

7일·30일 추이는 추이·통계 탭에서 확인하세요.