Files
control/README.md
T

14 KiB

Control

팬 제어, 시스템 모니터링, WiFi 제어, WakeLock, Home Assistant 알림을 제공하는 PHP 기반 단일 관리 패널입니다.

프로젝트 성격

Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 웹에서 관리하기 위한 내부 운영 도구입니다. 로그인 후 대시보드에서 온도, 팬 RPM, PWM, WiFi client, 배터리, notice, dmesg, process 후보를 확인하고 필요한 제어 명령을 실행합니다.

상태 갱신은 WebSocket을 우선 사용하고, 연결 실패 시 HTTP fallback으로 전환합니다. 팬 정책 적용과 센서 수집은 백그라운드 작업과 API 호출을 통해 DB에 기록됩니다.

주요 기능

  • 팬 모드 auto, manual, off 제어
  • PWM slider 기반 수동 팬 제어
  • CPU/RP1 온도, 팬 RPM, 팬 효율, CPU 전력, 배터리 상태 차트
  • 배터리 잔여 시간은 1S8P 병렬팩 2200mAh x 8 = 17600mAh, nominal 3.7V, 총 65.12Wh 기준으로 계산
  • 라즈베리파이 저전압/스로틀링 현재 상태, 복구 중/반복 발생 판정, 부팅 후 이력, 최근 감지 시각, 지속시간, 최근 10분 통계 표시
  • WiFi client 목록과 2.4G/5G client 수 표시
  • 5G 외부 WiFi 모듈이 연결 시간을 제공하지 않는 경우 서버 관측 기반 연결 시간 보정
  • System Notice와 process CPU/MEM 후보 표시
  • /etc/systemd/system/*.service 기준 사용자 생성 서비스의 서비스명, 현재 상태, enable 상태, PID, restart 횟수, 최근 journal 로그 표시
  • dmesg 로그 열람
  • Home Assistant webhook 기반 Android 모바일 알림
  • 배터리 SOC 20% 이하 경고를 20/15/10/5% 단계로 구분하고 동일 tag로 갱신해 알림이 과도하게 쌓이지 않도록 처리
  • 배터리 SOC가 20%를 초과해 복구되면 같은 tag의 Android 알림을 clear_notification으로 제거
  • 최근 HA 알림 발송 성공/실패 이력을 대시보드에 표시
  • WakeLock 버튼으로 대시보드 화면 꺼짐 방지
  • Reboot 버튼으로 2단계 확인 후 시스템 재부팅 요청
  • 기본 브라우저 alert/confirm/prompt 대신 대시보드 디자인에 맞춘 custom dialog 사용
  • custom dialog는 Enter/Escape 키 입력을 자체 처리하며, Reboot 확인 흐름은 중복 실행을 차단
  • Translate 버튼으로 en, ko UI 언어 토글
  • Theme 버튼으로 dark, light UI 테마 토글

주요 API

  • public/api.php?action=status: 팬, 센서, 시스템, WiFi, history, notice 상태 조회
  • public/api.php?action=collect: 센서 snapshot 수집 후 팬 정책 적용
  • public/api.php?action=fan: 팬 모드와 PWM 저장/적용
  • public/api.php?action=wifi: 허용된 WiFi/DHCP service 제어
  • public/api.php?action=dmesg: dmesg 로그 조회
  • public/api.php?action=reboot: 확인 단어와 관리자 암호 재검증 후 sudo reboot 실행

구성

  • public/index.php: 로그인과 관리 화면
  • public/api.php: 상태 조회와 조작 API
  • public/assets/app.js: 대시보드 렌더링, WebSocket, 차트, 조작 이벤트
  • public/assets/wakelock.js: Screen Wake Lock API 제어
  • config/config.php: DB, 인증, CSRF, HA 알림, shell 실행 공통 함수
  • apply_policy.php: CLI/cron 팬 정책 적용
  • bin/control_ws.php: WebSocket 서버. 핵심 PHP 파일 변경 감지 시 종료되고 systemd가 재시작해 새 코드를 로드
  • bin/ha_notify_channel.php: Android 알림 채널 제거 명령 전송용 운영 CLI
  • bin/wifi_observe.php: 5G WiFi 연결 시간 보정을 위한 시스템단 관측 CLI
  • systemd/control-wifi-observe.*: WiFi 관측 CLI를 주기적으로 실행하는 systemd unit 예시

데이터/저장소

  • control_state: 팬 모드와 PWM 상태
  • sensor_logs: 온도, RPM, PWM, 배터리, load, memory, disk, uptime
  • /tmp/control-low-voltage-state.json: vcgencmd get_throttled 기반 저전압 감지 상태, 최근 지속시간, 최근 episode 이력
  • /tmp/control-throttling-state.json: vcgencmd get_throttled 기반 스로틀링 감지 상태, 최근 지속시간, 최근 episode 이력
  • system_notice_state: notice 활성 상태와 기준값
  • system_notice_logs: notice 발생 이력
  • wifi_observed_sessions: 5G WiFi client의 최초/마지막 감지 시간
  • ha_notify_logs: HA webhook 알림 발송 성공/실패 이력, 대상 서버, HTTP code, tag, 메타 정보
  • /home/seo/secret/control.php: 앱 비밀번호, DB 설정, 배터리 설정, HA 알림 설정
  • 배터리 용량 설정은 /home/seo/secret/control.phpbattery.cell_capacity_mah, battery.parallel_cells, battery.nominal_voltage, battery.capacity_wh를 사용합니다.

HA 알림 구조

Control은 서버에서 Home Assistant webhook으로 알림 payload를 보내고, HA 자동화가 notify.mobile_app_seocaegeonyi_z_fold7 서비스로 Android 알림을 전달합니다.

  • webhook id: /home/seo/secret/control.phpha_notify.webhook_id
  • 기본 발송 순서: 서울 HA https://ha.seoul.chaegeon.com 우선, 실패 시 목포 HA https://ha.chaegeon.com
  • payload 형식: title, message, data
  • Android 알림 속성은 data에 넣어 HA mobile app으로 전달
  • 사용 속성: tag, group, channel, importance, priority, ttl, sticky, persistent, renotify, color, notification_icon, vibrationPattern, ledColor, visibility, timeout, clickAction, url, actions
  • 발송 결과는 ha_notify_logs에 저장

배터리 SOC 20% 이하 경고는 control-battery-low tag를 사용합니다. SOC 값이 조금씩 달라져도 Android 알림은 같은 tag로 갱신되어 알림 목록에 여러 장이 계속 쌓이지 않습니다. 20% 이하에서는 주의, 15% 이하에서는 경고, 10% 이하에서는 위험, 5% 이하에서는 긴급 단계로 채널, 중요도, 아이콘, 진동 패턴을 조정합니다. SOC가 20%를 초과하면 clear_notification으로 해당 tag 알림을 제거합니다.

System Notice는 control-system-notice tag를 사용하며, 기본 10분 쿨다운으로 급격한 팬/온도 변화 알림을 제한합니다. 쿨다운은 /home/seo/secret/control.phpha_notify.cooldowns에서 조정할 수 있습니다.

Android 알림 채널은 생성 후 휴대폰 설정에 의해 중요도와 진동 패턴이 고정될 수 있습니다. 채널을 다시 만들 필요가 있을 때는 운영 CLI로 제거 명령을 보낸 뒤 다음 알림에서 재생성합니다.

/usr/bin/php /var/www/control/bin/ha_notify_channel.php --remove=control_battery

WiFi 관측 자동화

5G 외부 WiFi 모듈은 iw station dumpconnected time을 제공하지 않는 경우가 있어, 서버가 MAC별 최초 감지 시각을 DB에 저장하고 경과 시간을 계산합니다.

기존 대시보드 조회만으로도 보정은 가능하지만, 사용자가 접속하지 않은 시간에는 최초 감지가 늦어질 수 있습니다. 이를 막기 위해 다음 systemd timer가 10초마다 관측 CLI를 실행합니다.

control-wifi-observe.timer
control-wifi-observe.service

실행 명령은 다음과 같습니다.

/usr/bin/php /var/www/control/bin/wifi_observe.php

이 작업은 팬 정책, 차트 로그 저장, HA 알림 발송과 분리되어 있으며 WiFi client 목록 확인과 wifi_observed_sessions 갱신만 수행합니다.

처리 흐름

  1. 화면 진입 시 로그인 세션과 remember token을 확인합니다.
  2. 대시보드는 status snapshot을 렌더링합니다.
  3. WebSocket 연결이 성공하면 status 메시지로 갱신하고, 실패하면 HTTP fallback을 사용합니다.
  4. 팬 조작은 상태 저장, 정책 적용, 로그 저장 순서로 처리합니다.
  5. WiFi client 목록은 iw station dump와 dnsmasq lease를 조합하고, 5G 연결 시간이 N/A이면 MAC 기준 최초 감지 시간을 DB에 저장해 경과 시간을 계산합니다.
  6. control-wifi-observe.timer는 사용자 접속과 무관하게 10초마다 5G 관측 세션을 갱신합니다.
  7. WakeLock 버튼은 활성 상태를 초록색 버튼으로 표시합니다.
  8. Reboot 버튼은 재부팅 단어 입력과 관리자 암호 재입력을 모두 통과한 뒤 서버 API로 재부팅을 요청합니다.
  9. 시스템 상태는 vcgencmd get_throttled를 읽어 현재 저전압/스로틀링 여부와 부팅 후 이력, 최근 감지 시각, 현재/최근 지속시간을 표시합니다.
  10. 저전압/스로틀링 상태 파일에는 최근 episode 시작/종료를 보관하고, 최근 10분 발생 횟수, 감지 누적시간, 감지 비율을 계산합니다.
  11. 배터리 SOC 또는 System Notice 조건이 맞으면 Control이 HA webhook으로 알림을 발송하고 ha_notify_logs에 결과를 저장합니다.
  12. 대시보드는 최근 HA 알림 성공/실패 이력을 ha_notify_logs에서 읽어 표시합니다.

주요 함수/모듈

  • collect_snapshot(): 센서와 fan 상태 snapshot 생성
  • custom_systemd_services(): /etc/systemd/system/*.service 단위를 조회해 사용자 생성 서비스 상태와 최근 journal 로그를 구성
  • systemd_service_logs(): 서비스별 최근 journal 로그 조회
  • read_throttled_flags(): vcgencmd get_throttled를 직접 조회하고, 권한 문제로 실패하면 sudo 경유 조회를 시도
  • throttled_event_status(): 저전압/스로틀링 episode 이력, 복구 중/반복 발생 판정, 최근 10분 통계를 계산
  • throttled_statuses(): 라즈베리파이 throttled flag를 읽고 저전압/스로틀링 감지 이력을 상태 파일로 추적
  • apply_fan_policy(): 팬 목표값 계산과 적용
  • json_out(): API JSON 응답 표준화
  • apply_observed_wifi_connected_time(): 5G WiFi 연결 시간이 없는 client에 서버 관측 경과 시간 적용
  • send_ha_notify(): HA webhook 알림 발송, 서울 우선/목포 fallback, 성공/실패 로그 저장
  • ha_notify_due(): 동일 tag 기준 쿨다운 판정
  • clear_ha_notification(): 같은 tag의 Android 알림 제거 명령 발송
  • battery_low_notify_profile(): 배터리 SOC 단계별 채널, 중요도, 아이콘, 진동 정책 선택
  • send_battery_low_notify_if_needed(): 배터리 SOC 20% 이하 알림 발송
  • ha_notify_log_rows(): 대시보드 HA 알림 이력 조회
  • bin/ha_notify_channel.php: Android 알림 채널 제거 명령 CLI
  • bin/wifi_observe.php: 화면 접속 없이 wifi_data()를 호출해 5G 관측 세션을 선제 갱신
  • assets/wakelock.js: WakeLock 버튼 상태와 Screen Wake Lock API 제어
  • customAlert(), customConfirm(), customPrompt(): 대시보드 공통 확인/입력 dialog
  • controlLang, controlTheme: 재접속 후에도 유지되는 언어/테마 localStorage key
  • BATTERY_CELL_CAPACITY_MAH, BATTERY_PARALLEL_CELLS, BATTERY_CAPACITY_MAH, BATTERY_NOMINAL_VOLTAGE, BATTERY_CAPACITY_WH: 병렬 배터리팩 용량과 잔여시간 계산 기준

보안

  • 로그인 세션과 CSRF token을 사용합니다.
  • POST 조작 API는 CSRF 검증을 통과해야 합니다.
  • sysfs 쓰기와 systemctl 실행 권한은 sudoers 범위로 제한해야 합니다.
  • 재부팅 API는 CSRF, 로그인 세션, 확인 단어 재부팅, 관리자 암호 재검증을 모두 요구합니다.
  • 앱 비밀번호와 HA 알림 설정은 저장소 밖 secret 파일로 관리합니다.
  • HA webhook id는 /home/seo/secret/control.phpha_notify.webhook_id에 둡니다. 값이 없으면 발송하지 않고 ha_notify_logs에 실패로 기록합니다.

운영 체크포인트

  • 센서 수집 주기와 DB 증가량을 확인합니다.
  • 배터리팩 변경 시 /home/seo/secret/control.phpbattery 값을 먼저 갱신합니다. 현재 기준은 2200mAh x 8 parallel = 17600mAh, nominal 65.12Wh입니다.
  • 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다.
  • 2.4G 내장 WiFi는 hostapd-24g.service 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다.
  • 5G WiFi 연결 시간은 외부 모듈이 값을 제공하지 않을 때 서버가 처음 감지한 시각 기준으로 계산합니다. 현재 5G 목록에서 MAC이 사라지면 관측 세션을 즉시 종료하므로 재연결 시 0부터 다시 누적됩니다.
  • control-wifi-observe.timer는 10초마다 /var/www/control/bin/wifi_observe.php를 실행해 사용자가 대시보드에 접속하지 않아도 5G 연결 시간 카운터를 시작하고 유지합니다.
  • WebSocket은 장기 실행 프로세스이므로 public/api.php, config/config.php, bin/control_ws.php 변경을 감지하면 15초 안에 종료되고 control-websocket.service가 새 프로세스로 재시작합니다.
  • WebSocket 장기 실행 중 DB 연결이 끊길 수 있으므로 reconnect 로그를 확인합니다.
  • HA 알림 자동화는 서울 /home/seo/homeassistant/automations.yaml, 목포 /mnt/synology-docker/homeassistant/config/automations.yaml 양쪽의 CONTROL_HA_NOTIFY_WEBHOOK 계열 항목에서 관리합니다.
  • SmartThings 재로드 자동화는 서울 전력분전반과 목포 누전차단기 전력 센서의 값이 10초 이상 변하지 않으면 통합을 재로드합니다.
  • HA 알림 채널의 중요도나 진동이 예상과 다르면 휴대폰 알림 채널 설정을 확인하거나 bin/ha_notify_channel.php로 해당 채널 제거 명령을 보냅니다.
  • Reboot API 사용 전 웹 서버 실행 계정의 sudoers에 /usr/sbin/reboot 비밀번호 없는 실행 권한이 제한적으로 설정되어 있는지 확인합니다.
  • 저전압/스로틀링이 N/A로 보이면 웹 서버 실행 계정의 /dev/vcio 접근 권한과 /usr/bin/vcgencmd get_throttled sudoers 허용 여부를 확인합니다.
  • 언어/테마 표시가 예상과 다르면 브라우저 localStorage의 controlLang, controlTheme 값을 확인합니다.