Files
car/README.md
T

13 KiB

Car

차량 상태 조회, TCP 명령 전송, 모니터링, 데이터 사용량 표시를 제공하는 PHP 기반 차량 서비스입니다.

프로젝트 성격

Car는 차량 모뎀/게이트웨이에서 받은 상태를 수집해 DB에 저장하고, 웹 화면과 API에서 최신 상태와 명령 실행 결과를 제공하는 내부 차량 관리 서비스입니다.

모뎀에서 제공되는 값의 한계가 있으므로 도어 잠김, 경계, 시동, 공조 상태는 여러 필드를 조합해 해석합니다. 통신사 사용량은 TCP payload 수집값, 통신사 과금 단위 추정값, T world 기준 보정값을 함께 사용합니다.

주요 기능

  • 차량 상태 수집과 저장
  • 차량 상태 API
  • 허용된 차량 명령 TCP 전송
  • monitor 화면과 AJAX 상태 갱신
  • monitor 화면 WakeLock, 언어, 테마 토글
  • monitor 좌측 상단 이전 페이지 복귀 링크
  • 모바일 및 좁은 카드 폭에 맞춘 사용량 2줄 배치, 로그 가로 스크롤, 시간 문구 축약
  • 사용량/요금 표시와 통신사 과금 단위 보정 metadata
  • 4.95초 UI timeout과 60초 사용량 정산 분리
  • TCP 실패 reason과 마지막 수신 지연 표시
  • 수집 공백을 반영한 차량 상태 경과 시간 표시
  • 도어/경계/시동/공조 상태 해석
  • 실시간 차량 도어/트렁크 열림 표시
  • PWA icon 제공

주요 API

  • api.php?action=status: 차량 상태 조회
  • api.php?action=command: 차량 명령 전송
  • monitor.php?mode=ajax: monitor 상태 AJAX
  • monitor.php?mode=usage: 데이터 사용량 AJAX
  • monitor.php?mode=usage-calibration: 관리자 전용 데이터 사용량 보정 기준점 조회/저장
  • monitor.php?mode=auth-login: 브라우저 직접 접근 비밀번호 화면용 공통 암호 검증

Monitor 경과 시간

monitor.php?mode=ajaxmeta.state_duration은 현재 시동 상태가 연속으로 유지된 시간입니다. 화면의 시동 카드 문장은 이 값을 사용해 시동 켜짐/꺼짐 경과를 표시합니다.

meta.engine_state_duration도 같은 기준의 값을 함께 내려주어 내부 확인과 호환성을 유지합니다.

상태 기록 섹션의 경과는 각 로그가 기록된 시각부터 현재까지 흐른 시간입니다. 각 행의 age_seconds는 서버 현재시각과 로그 timestamp의 차이로 계산해 내려주며, 화면 갱신마다 상단 조회 주기 경과처럼 계속 증가합니다.

모바일처럼 화면이나 상태 카드 폭이 좁을 때는 조회 경과와 시동 유지 시간이 한 줄로 유지되도록 초, 필요 시 분 단위를 생략해 표시합니다. 사용량 지표는 3열 2줄로 카드 안에 배치하고, 상태 기록 테이블은 카드 내부 좌우 스크롤로 분리해 전체 페이지 레이아웃이 밀리지 않게 합니다.

실시간 차량 그림의 도어/트렁크 열림 표시선은 열림 애니메이션 중에도 차량 기준 위치를 유지합니다. 트렁크 표시선은 중앙 정렬 기준을 유지한 상태에서 확대되어 PC와 모바일 모두에서 차체 하단과 맞도록 표시됩니다.

Monitor 화면 제어

헤더 우측 컨트롤은 WakeLock, 언어, 테마 순서입니다. WakeLock은 Screen Wake Lock API를 지원하는 브라우저에서 화면 꺼짐을 방지하며, 활성 상태는 초록색 아이콘 버튼으로 표시합니다. 사용자의 선택은 localStorage에 저장하고, 새로고침이나 탭 복귀 후에는 브라우저 정책에 맞춰 다시 획득을 시도합니다.

좌측 상단 복귀 링크는 이전 페이지가 chaegeon.com 계열이면 해당 URL을 사용합니다. chaegeon.com이면 채건닷컴, /blog이면 블로그처럼 알려진 경로명을 우선 표시하고, 같은 출처의 다른 이전 페이지는 문서 title을 읽어 표시합니다. 쿼리만 다른 같은 차량 모니터 화면은 건너뛰고, 직접 접속이나 이전 페이지 확인이 어려운 경우에는 https://chaegeon.com/를 기본 목적지로 사용합니다. seo.chaegeon.com의 상대 경로로 이동하지 않도록 절대 URL을 기본값으로 둡니다.

구성

  • api.php: 차량 상태/제어 API
  • asset-version.php: 차량 모니터 파일 묶음의 현재 hash를 내려주는 JSON 엔드포인트
  • monitor.php: 모니터링 화면과 AJAX 응답
  • common.php: 외부 secret 로드와 공통 DB/API 함수
  • collector_se.php: 상태 수집 CLI/cron
  • tcp_worker.php: TCP 큐 처리와 늦은 사용량 정산 worker
  • car-tcp-worker.service: systemd service 예시
  • sw.js: 과거 등록된 service worker 정리용 파일
  • assets/: 아이콘과 정적 자산

asset-version.php는 차량 모니터의 PHP/JS/CSS/manifest/icon 파일을 읽어 크기, 수정 시각, sha256 hash를 묶은 버전을 만듭니다. assets/asset-reload.js는 열린 모니터 화면에서 이 값을 확인하고, 달라지면 Cache Storage를 비우고 service worker 등록을 해제한 뒤 현재 화면을 다시 엽니다. 현재 URL의 assetReload 토큰이 최신 파일 묶음 hash와 다르면 첫 진입도 토큰을 붙인 URL로 다시 열어 낡은 JS/CSS가 먼저 실행되는 상황을 줄입니다. 모바일/삼성 브라우저 호환을 위해 화면 복귀, 온라인 복귀, 터치/클릭 복귀 이벤트도 확인하고, Web Storage 실패 시 쿠키 fallback으로 이전 버전을 비교합니다.

monitor.php는 남은 service worker 등록을 해제합니다. 차량 상태와 인증 요청은 실시간 응답이 중요하므로 브라우저 오프라인 캐시를 사용하지 않습니다.

데이터/저장소

  • Car DB tables: 차량 상태, 로그, 차트용 기록, TCP 요청 큐
  • 사용량 수집값, 통신사 과금 단위 추정값, 월별 보정 기준
  • /home/seo/secret/car.php: TCP, DB, token, 허용 IP 설정

처리 흐름

  1. collector_se.php가 차량 상태를 수집해 DB에 저장합니다.
  2. monitor.php는 상태 AJAX와 사용량 AJAX를 분리해 갱신합니다.
  3. 제어 요청은 token/IP 정책을 검증합니다.
  4. 명령 코드를 허용 목록과 대조합니다.
  5. 요청을 car_tcp_request_queue에 저장합니다.
  6. car-tcp-worker.service가 큐를 처리하며 TCP 게이트웨이로 전송합니다.
  7. API는 큐 상태를 4.95초까지만 기다린 뒤 결과 또는 timeout을 반환합니다.

TCP timeout과 사용량 정산

차량 명령 성공/실패 판단은 UI 안정성을 위해 TCP_TOTAL_TIMEOUT 기본값인 4.95초를 사용합니다. 이 시간 안에 정상 응답이 없으면 API는 기존처럼 실패를 반환하므로 자동화와 UI는 즉시 재시도 여부를 판단할 수 있습니다.

단, 실제 모뎀이 4.95초 이후에 늦게 응답할 수 있으므로 사용량 기록은 별도로 정산합니다. API는 요청을 DB 큐에 넣고 4.95초까지만 기다립니다. car-tcp-worker.service는 해당 요청의 TCP 연결을 직접 열고, UI timeout 이후에도 같은 소켓을 최대 TCP_USAGE_SETTLEMENT_TIMEOUT 기본 60초까지 더 관찰합니다.

  • 60초 안에 정상 응답이 완성되면 late_response_after_ui_timeout으로 송신량과 수신량을 함께 기록합니다.
  • 60초까지 응답이 없으면 late_total_timeout_60s_sent_only로 송신 패킷만 사용량에 반영합니다.
  • 60초 안에 일부 데이터만 오고 정상 포맷이 아니면 late_invalid_or_partial_response로 실제 수신된 바이트까지 기록합니다.
  • 늦은 정상 응답이 차량 상태 포맷이면 상태 DB에도 저장합니다.

이 구조에서 request_id는 UI 응답과 늦은 사용량 정산 기록을 연결하는 기준입니다. 즉 명령 재시도 로직은 4.95초 기준을 유지하고, 데이터 사용량은 최대 60초까지 늦은 수신 패킷을 반영합니다.

systemd worker

설치 파일은 car-tcp-worker.service입니다.

cp /var/www/seoul/car/car-tcp-worker.service /etc/systemd/system/car-tcp-worker.service
systemctl daemon-reload
systemctl enable --now car-tcp-worker.service
systemctl status car-tcp-worker.service

큐 테이블은 코드에서 자동 생성합니다. Worker가 중지되면 API 요청은 큐에 쌓이지만 4.95초 안에 처리되지 않아 실패로 반환될 수 있습니다. 안전을 위해 worker가 뒤늦게 오래된 queued 요청을 발견하면 실제 TCP 송신 없이 queue_expired_before_send로 만료 처리합니다.

Worker 교체나 예외 종료로 processing, ui_timeout_pending 상태가 남으면 다음 claim 전에 stale queue를 복구합니다. 전송 전이면 expired_before_send, 이미 TCP payload를 보낸 상태면 settled_sent_only로 정산해 사용량 누락을 막습니다.

주요 함수/모듈

  • common.php: secret 로드와 공통 DB/API 함수
  • api.php: 상태 조회와 명령 전송
  • monitor.php: 화면 렌더링과 AJAX 응답
  • collector_se.php: 상태 수집과 중복 실행 방지
  • tcp_worker.php: TCP 요청 큐 처리와 60초 사용량 정산

보안

  • 차량 API는 API token 또는 허용 IP 정책을 사용합니다.
  • 차량 모니터 화면과 monitor.php?mode=ajax, monitor.php?mode=usage는 런처 공통 인증 쿠키 또는 사이트 관리자 세션이 유효할 때만 응답합니다.
  • 공통 암호로 로그인한 일반 인증은 30분 유지하고, 사이트 관리자 세션이 확인되면 관리자 장기 쿠키를 발급해 PWA에서 반복 인증이 뜨는 일을 줄입니다.
  • PWA로 설치한 차량 모니터는 manifest 시작 URL /car/monitor.php?pwa=1로 진입합니다. 이 요청은 기존 공통 인증 쿠키가 있으면 유지하고, 사이트 관리자 세션이면 관리자 쿠키를 발급한 뒤 /car/monitor.php로 되돌아가므로 설치형 앱 진입 때 반복 PIN 화면이 뜨는 일을 줄입니다.
  • 런처 공통 인증은 우선 공통 인증 모듈로 직접 확인합니다. 공통 모듈을 사용할 수 없는 경우에만 https://chaegeon.com/custom/launcher/api.php?session=1 응답으로 확인합니다.
  • 브라우저로 직접 접근했는데 인증이 없으면 채건닷컴으로 보내지 않고 /custom/common/js/auth-pin.js의 4자리 숫자 PIN 화면을 표시합니다. 차량 모니터는 seo.chaegeon.com에서 동작하므로 화면 입력값을 monitor.php?mode=auth-login으로 보내 공통 암호를 검증하고, 인증이 끝나면 차량 모니터를 다시 불러옵니다.
  • 차량 모니터의 브라우저 화면 인증은 런처/나의 찾기와 같은 공통 쿠키를 사용하지만, 차량 단말이 호출하는 api.php 인증은 API token과 허용 IP 정책을 사용하는 별도 경로입니다.
  • 차량 제어 명령은 허용된 명령 코드로 제한합니다.
  • Secret 파일은 저장소 밖에서 제한된 권한으로 유지합니다.
  • 실제 제어 명령은 최신 상태 조회와 명령 검증 이후에만 전송합니다.

운영 체크포인트

  • 차량 TCP 실패 reason과 마지막 수신 지연을 확인합니다.
  • 명령별 rate limit과 감사 로그를 유지합니다.
  • 통신사 기준 데이터 사용량 보정값을 주기적으로 확인합니다. 2026-06-30 15:15 T world 실측 114.5MB(117,250.5KB) 기준 2026-06 보정값은 통신사 누적 120,064,512 bytes, 통신사 과금 단위 추정 누적 129,148,416 bytes, 배율 0.929663입니다.
  • 2026-07-02 12:42 T world 실측 6.25MB(6,396KB) 기준 2026-07 보정값은 통신사 누적 6,549,504 bytes, 통신사 과금 단위 추정 누적 7,169,536 bytes, 배율 0.913519입니다.
  • 관리자 인증 상태에서는 상단 우측 설정 아이콘으로 T world 사용량 기준점을 저장할 수 있습니다. 입력값은 car_usage_calibrations 테이블에 저장되고, 같은 월에서는 가장 최근 기준 시각의 값을 우선 사용합니다.
  • 해당 월의 T world 기준점이 DB나 코드 기준점에 있으면 그 월 배율을 우선 사용하고, 아직 기준점이 없는 새 달은 가장 최근 월 배율을 임시로 사용합니다. 새 기준점이 기록되면 해당 월 배율로 다시 계산합니다.
  • 2026-06 기준 시각의 로컬 계측 범위는 2026-06-01 00:00:00부터 2026-06-30 15:15:00 직전까지이며, 마지막 로컬 사용량 기록은 2026-06-30 15:14:59입니다.
  • 데이터 사용량은 TCP payload 합계도 보존하지만 화면의 현재 사용량, 잔여 사용량, 예상 사용량, 예상 요금은 0.5KB 과금 단위로 올림 처리한 통신사형 누적값을 우선 사용합니다. 순수 연결 실패와 마지막 성공 이후 60초를 넘긴 수신 공백은 기존처럼 제외합니다.
  • 데이터 사용량 집계는 성공 응답 평균을 SQL로 먼저 구하고, 월간/일간 행은 PHP에서 한 줄씩 스트리밍 처리합니다. 기존 보정 조건은 유지하면서 fetchAll() 메모리 사용을 제거해 PHP-FPM memory_limit=128M에서도 동작하도록 합니다.
  • 4.95초 timeout 직후에는 사용량 기록이 즉시 생기지 않을 수 있으며, 최대 60초 뒤 늦은 정산 행이 추가될 수 있습니다.
  • systemctl status car-tcp-worker.servicejournalctl -u car-tcp-worker.service로 worker 상태를 확인합니다.