From 0966f6d32bd8f23ab9e3f66cfced042b79c5e70d Mon Sep 17 00:00:00 2001 From: cw2007 Date: Sat, 11 Jul 2026 11:22:40 +0900 Subject: [PATCH] =?UTF-8?q?feat(sensor):=20=EC=84=BC=EC=84=9C=EB=B3=84=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=20=EB=9D=BC=EB=B2=A8(=EC=9C=84=EC=B9=98?= =?UTF-8?q?=C2=B7=EA=B4=80=EB=A6=AC=EC=A3=BC=EC=B2=B4)=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=EC=B8=A1=20=EC=98=A4=EB=B2=84=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SENSOR_LABELS(config.local.php) 로 센서별 위치·관리주체를 서버에서 지정하고, sensor_label() 헬퍼로 SMS·대시보드 표시를 통일한다(Pi 재배포 불필요). SMS 본문 라벨을 '센서'→'관리주체'로 변경. 배포 번들에 3개 센서(서버실 안/문서고/밖) 예시 SENSOR_LABELS 를 주입. --- php/config.php | 44 ++++++++++++++++++++++++++++++++++++ php/sms_send.php | 42 ++++++++++++++-------------------- tools/make_deploy_bundles.py | 7 ++++++ 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/php/config.php b/php/config.php index 9c3563c..4025d13 100644 --- a/php/config.php +++ b/php/config.php @@ -264,6 +264,50 @@ $metric_sensor_ids = array_values(array_filter( )); define('METRIC_SENSOR_IDS', $metric_sensor_ids !== [] ? $metric_sensor_ids : [2]); +// ─── 센서별 표시 라벨 오버라이드 (서버측) ──────────────────── +// SMS·대시보드에 표시할 센서별 "위치"와 "관리주체(표시명)"를 서버에서 지정한다 +// (Pi 재배포 없이 config.local.php 만 바꾸면 됨). 지정이 없으면 Pi 가 보고한 +// device_location / sensor_name 을 그대로 쓴다. 예: +// 'SENSOR_LABELS' => [ +// 1 => ['location' => '서버실(안)', 'name' => '정보기반'], +// 2 => ['location' => '문서고', 'name' => '조직혁신'], +// 3 => ['location' => '서버실(밖)', 'name' => '고객센터'], +// ] +$sensor_labels_raw = cfg('SENSOR_LABELS', []); +$sensor_labels = []; +if (is_array($sensor_labels_raw)) { + foreach ($sensor_labels_raw as $sid => $lbl) { + $sid = (int)$sid; + if ($sid < 1 || $sid > 255 || !is_array($lbl)) { + continue; + } + $entry = []; + if (isset($lbl['location']) && is_string($lbl['location']) && $lbl['location'] !== '') { + $entry['location'] = $lbl['location']; + } + if (isset($lbl['name']) && is_string($lbl['name']) && $lbl['name'] !== '') { + $entry['name'] = $lbl['name']; + } + if ($entry !== []) { + $sensor_labels[$sid] = $entry; + } + } +} +define('SENSOR_LABELS', $sensor_labels); + +/** + * 센서 표시 라벨 결정: SENSOR_LABELS(서버 오버라이드) 우선, 없으면 보고값(Pi) 폴백. + * SMS·대시보드 등 사람이 보는 모든 곳에서 센서의 위치/관리주체를 이 헬퍼로 얻는다. + * + * @return array{0:string,1:string} [위치, 관리주체(표시명)] + */ +function sensor_label(int $sensor_id, ?string $reported_location, ?string $reported_name): array { + $ov = SENSOR_LABELS[$sensor_id] ?? []; + $loc = $ov['location'] ?? ((($reported_location ?? '') !== '') ? $reported_location : '알 수 없음'); + $name = $ov['name'] ?? ((($reported_name ?? '') !== '') ? $reported_name : "센서{$sensor_id}"); + return [$loc, $name]; +} + // ─── 대시보드 세션 인증 ────────────────────────────────── define('ADMIN_USER', cfg('ADMIN_USER', 'admin')); define('ADMIN_PASSWORD_HASH', cfg('ADMIN_PASSWORD_HASH', '')); // bcrypt 해시 diff --git a/php/sms_send.php b/php/sms_send.php index 1890620..c00b8ce 100644 --- a/php/sms_send.php +++ b/php/sms_send.php @@ -182,7 +182,7 @@ function send_sms_cafe24(string $receiver, string $message): array { * @return bool 전원 발송 성공 여부 */ function sms_dispatch_to_recipients(PDO $db, array $sensor_data, string $message, string $logLabel, ?array $recipients = null): bool { - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_data['sensor_id']}"; + [, $name] = sensor_label((int)($sensor_data['sensor_id'] ?? 0), null, $sensor_data['sensor_name'] ?? null); $allSuccess = true; $lastRemaining = null; // 게이트웨이가 알려준 최신 잔여 건수(잔액 사전경보용) $targets = $recipients ?? SMS_RECIPIENTS; // 기본 1차, 에스컬레이션은 TIER2 전달 @@ -520,14 +520,13 @@ function send_metric_alert_sms(array $sensor_data, string $kind, float $value): // ── 메시지 구성 ────────────────────────────────────────── $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_id}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $valStr = metric_value_str($value); $thrStr = metric_value_str((float)$threshold); $message = "{$tag}\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "{$metricName}: {$valStr}{$unit} (임계 {$thrStr}{$unit} {$dir})\n" . "시각: {$dt}"; @@ -555,12 +554,11 @@ function send_metric_recovery_sms(array $sensor_data, float $temp_c, float $rh): $db = get_db(); $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_data['sensor_id']}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $message = SMS_TAG_RECOVERY . "\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "온도 " . metric_value_str($temp_c) . "℃ / 습도 " . metric_value_str($rh) . "%\n" . "시각: {$dt}\n" . "온습도가 정상 범위로 복귀했습니다."; @@ -632,12 +630,11 @@ function send_leak_alert_sms(array $sensor_data): bool { // ── 메시지 구성 ── $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_id}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $message = SMS_TAG_LEAK_ALERT . "\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "누수가 감지되었습니다. 즉시 확인하세요!\n" . "시각: {$dt}"; @@ -685,12 +682,11 @@ function send_leak_recovery_sms(array $sensor_data): bool { } $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_id}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $message = SMS_TAG_LEAK_RECOVERY . "\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "누수가 해소(복구)되었습니다.\n" . "시각: {$dt}"; @@ -707,13 +703,12 @@ function send_device_offline_sms(array $sensor_data): bool { $db = get_db(); $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_data['sensor_id']}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $last = $sensor_data['last_seen'] ?? '알 수 없음'; $message = SMS_TAG_DEVICE_OFFLINE . "\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "마지막 통신: {$last}\n" . "감지 시각: {$dt}\n" . "장비 상태를 확인하세요!"; @@ -731,12 +726,11 @@ function send_device_online_sms(array $sensor_data): bool { $db = get_db(); $dt = date('Y-m-d H:i:s'); - $name = $sensor_data['sensor_name'] ?? "센서{$sensor_data['sensor_id']}"; - $loc = $sensor_data['device_location'] ?? '알 수 없음'; + [$loc, $name] = sensor_label((int)$sensor_data['sensor_id'], $sensor_data['device_location'] ?? null, $sensor_data['sensor_name'] ?? null); $message = SMS_TAG_DEVICE_ONLINE . "\n" . "위치: {$loc}\n" - . "센서: {$name}\n" + . "관리주체: {$name}\n" . "복구 시각: {$dt}\n" . "통신이 정상 복구되었습니다."; @@ -920,11 +914,10 @@ function maybe_escalate_alerts(PDO $db): void { continue; } $firstLine = strtok($msg, "\n"); - $name = $s['sensor_name'] ?: "센서{$sid}"; - $loc = $s['device_location'] ?: '알 수 없음'; + [$loc, $name] = sensor_label($sid, $s['device_location'] ?? null, $s['sensor_name'] ?? null); $mins = (int)floor((time() - strtotime((string)$row['sent_at'])) / 60); $message = SMS_TAG_ESCALATION . "\n" - . "위치: {$loc}\n센서: {$name}\n" + . "위치: {$loc}\n관리주체: {$name}\n" . "{$firstLine} 미복귀 {$mins}분 경과\n" . "1차 미대응 — 확인 바랍니다.\n시각: " . date('Y-m-d H:i:s'); $info = ['sensor_id' => $sid, 'sensor_name' => $name, 'device_id' => $s['device_id'], 'device_location' => $loc]; @@ -969,11 +962,10 @@ function maybe_detect_stuck_sensors(PDO $db): void { if (recent_tag_within($db, $sid, SMS_TAG_SENSOR_STUCK, STUCK_ALERT_COOLDOWN_SEC)) { continue; // 쿨다운 } - $name = $s['sensor_name'] ?: "센서{$sid}"; - $loc = $s['device_location'] ?: '알 수 없음'; + [$loc, $name] = sensor_label($sid, $s['device_location'] ?? null, $s['sensor_name'] ?? null); $tval = number_format((float)$rows[0]['temperature_c'], 2); $hval = number_format((float)$rows[0]['humidity_percent'], 2); - $message = SMS_TAG_SENSOR_STUCK . "\n위치: {$loc}\n센서: {$name}\n" + $message = SMS_TAG_SENSOR_STUCK . "\n위치: {$loc}\n관리주체: {$name}\n" . "최근 {$n}회 측정값 고착(온도 {$tval}℃ / 습도 {$hval}%)\n" . "센서/배선 점검 필요\n시각: " . date('Y-m-d H:i:s'); $info = ['sensor_id' => $sid, 'sensor_name' => $name, 'device_id' => $s['device_id'], 'device_location' => $loc]; diff --git a/tools/make_deploy_bundles.py b/tools/make_deploy_bundles.py index 8a68f9b..5f160a9 100644 --- a/tools/make_deploy_bundles.py +++ b/tools/make_deploy_bundles.py @@ -309,6 +309,13 @@ return [ // -- leak module sensor_id (Site 1 + new Site 3) -- 'LEAK_SENSOR_IDS' => [1, 3], + // -- per-sensor display labels (location + managing entity) shown in SMS/dashboard -- + 'SENSOR_LABELS' => [ + 1 => ['location' => '서버실(안)', 'name' => '정보기반'], + 2 => ['location' => '문서고', 'name' => '조직혁신'], + 3 => ['location' => '서버실(밖)', 'name' => '고객센터'], + ], + // -- temperature/humidity thresholds (recommended operational values) -- 'METRIC_TEMP_HIGH_C' => 27, 'METRIC_TEMP_LOW_C' => 10,