BLE 차량 제어: GATT 연결과 저전력 통신을 안정화하는 방법
BLE는 차량과 휴대폰이 가까이 있을 때 작은 데이터를 주고받는 데 적합합니다. 디지털 키, 근거리 도어 제어와 차량 식별처럼 연결 시간이 짧고 배터리 소비를 줄여야 하는 기능에서 자주 사용됩니다.
다만 BLE라는 이름만으로 저전력 동작이 보장되지는 않습니다. 앱이 계속 주변을 검색하거나 연결을 불필요하게 유지하면 휴대폰과 차량 장치 모두 전력을 소비합니다. 안정적인 차량 제어를 만들려면 검색, 연결, 인증, 명령 전송과 해제까지 하나의 통신 상태로 설계해야 합니다.
BLE가 담당하는 범위를 먼저 나눕니다
휴대폰 BLE는 근거리 통신입니다. 차량과 멀리 떨어진 상태에서 실행하는 원격 제어는 일반적으로 앱이 서버에 명령을 보내고, 서버가 차량 통신 장치로 전달하는 경로가 필요합니다.
근거리 제어
휴대폰 앱 ⇄ BLE ⇄ 차량 장치
원거리 제어
휴대폰 앱 ⇄ 서비스 서버 ⇄ 차량 통신 장치두 경로가 같은 잠금이나 상태 조회 기능을 제공할 수는 있습니다. 그러나 연결 상태와 오류 의미는 다릅니다. BLE의 연결 실패를 서버 장애처럼 표시하거나, 서버 명령 대기 상태를 BLE 검색 중으로 표현하면 사용자는 무엇을 기다리는지 알기 어렵습니다.
통신 계층에서 경로를 구분하고 화면에는 차량 검색 중, 차량 연결 중, 명령 전달 중, 차량 응답 대기처럼 현재 단계를 번역해 주는 편이 좋습니다.
검색은 짧고 구체적으로 수행합니다
차량 장치는 Advertising 패킷으로 주변에 존재를 알리고, 휴대폰은 Scan을 통해 대상을 찾습니다. 검색 조건이 느슨하면 주변의 다른 BLE 장치까지 계속 처리하게 됩니다.
가능하면 서비스 UUID와 제조사 데이터처럼 프로토콜에서 정한 값으로 필터링합니다. 앱이 알고 있는 차량 식별자를 광고 데이터와 직접 비교할 때는 개인정보나 고정 식별자가 그대로 노출되지 않는지도 검토해야 합니다.
검색에는 명확한 종료 조건이 필요합니다.
- 원하는 차량을 찾으면 즉시 검색을 중단합니다.
- 정해진 시간이 지나면 실패 상태로 전환합니다.
- 화면을 벗어나거나 사용자가 취소하면 Scan을 해제합니다.
- 연결된 상태에서 중복 검색을 시작하지 않습니다.
무한 반복 검색은 배터리뿐 아니라 연결 품질에도 영향을 줍니다. 재시도는 즉시 반복하기보다 간격을 늘리고, Bluetooth 비활성화와 권한 거부처럼 기다려도 해결되지 않는 상태를 먼저 분리해야 합니다.
Central과 GATT Client는 같은 개념이 아닙니다
차량 제어에서 휴대폰은 보통 주변 장치를 찾고 연결을 시작하는 Central 역할을 맡습니다. 연결 후에는 차량이 제공하는 GATT Service와 Characteristic을 탐색하고 값을 읽거나 쓰기 때문에 GATT Client가 됩니다.
Central과 Peripheral은 연결을 어떻게 시작하는지에 관한 역할입니다. GATT Client와 Server는 연결 뒤 데이터를 누가 요청하고 제공하는지를 나타냅니다. 두 역할을 하나로 섞어 설명하면 연결 문제와 데이터 교환 문제를 구분하기 어려워집니다.
GATT 구조는 기능 단위로 나누는 편이 관리하기 쉽습니다.
Vehicle Control Service
Command Characteristic Write
Command Result Characteristic Notify
Vehicle State Characteristic Read, NotifyUUID만으로 의미를 암묵적으로 공유하지 말고 명령 종류, 버전, 요청 ID, 길이와 오류 코드를 별도 프로토콜로 정의해야 합니다. 앱과 차량 장치의 배포 시점이 다를 수 있으므로 하위 호환 정책도 필요합니다.
연결은 콜백 모음이 아니라 상태 기계입니다
BLE API는 검색 결과, 연결 완료, 서비스 탐색, Characteristic 변경과 연결 해제 이벤트를 비동기로 전달합니다. 각 콜백에서 다음 API를 바로 호출하는 방식은 화면 전환이나 재연결이 겹칠 때 상태가 꼬이기 쉽습니다.
Idle
↓
Scanning
↓
Connecting
↓
Discovering Services
↓
Authenticating
↓
Ready
↓
Sending Command
↓
Waiting Result모든 이벤트에는 현재 세션 식별자를 함께 확인해야 합니다. 이전 연결에서 늦게 도착한 콜백이 새 연결 상태를 덮어쓰지 않도록 하기 위해서입니다. 연결이 끊기면 어느 단계에서 실패했는지 기록하고, 재연결 후 서비스 탐색과 구독 설정을 다시 완료한 뒤에만 Ready로 전환합니다.
MTU보다 애플리케이션 프레임이 중요합니다
BLE에서 한 번에 보낼 수 있는 데이터 크기는 플랫폼과 연결 협상 결과에 따라 달라집니다. 큰 명령을 고정 크기로 가정해 한 번에 쓰면 일부 기기에서 잘리거나 실패할 수 있습니다.
프로토콜에는 전체 길이, 프레임 순서, 요청 ID와 무결성 확인값을 포함할 수 있습니다. 여러 조각으로 나눴다면 마지막 프레임을 보냈다는 사실과 차량이 전체 명령을 조립했다는 사실도 구분해야 합니다.
Write 완료 콜백은 운영체제의 전송 요청이 처리됐다는 의미일 수 있습니다. 실제 차량 기능이 실행됐다는 뜻은 아닙니다. 차량 장치가 반환하는 명령 결과를 별도 Characteristic 알림으로 받아야 사용자에게 완료 상태를 보여 줄 수 있습니다.
저전력 설정은 연결 단계마다 달라집니다
검색 중에는 Scan 빈도와 시간을 줄이는 것이 중요합니다. 연결 뒤에는 데이터가 없는 동안 긴 연결 간격이 전력 소비에 유리할 수 있고, 사용자가 제어 버튼을 누른 직후에는 빠른 응답을 위해 통신 빈도를 높일 수 있습니다.
이 값은 휴대폰 앱이 단독으로 결정하지 않습니다. 운영체제와 차량 장치가 지원 범위 안에서 연결 조건을 조정합니다. 특정 간격이 항상 적용된다고 가정하지 말고, 필요한 처리량과 응답 시간에 맞춰 프로토콜을 설계해야 합니다.
명령이 끝난 뒤에도 다음 동작이 곧 이어질 수 있다면 짧게 연결을 유지할 수 있습니다. 반대로 화면을 닫았는데 연결과 알림 구독을 계속 유지하면 배터리와 무선 자원을 소비합니다. 유지 시간은 기능별로 분리하고 앱 생명 주기와 함께 관리해야 합니다.
백그라운드에서는 같은 속도를 기대할 수 없습니다
iOS와 Android는 앱이 화면에 보이지 않을 때 Scan, 실행 시간과 프로세스 유지에 제약을 둡니다. 백그라운드 모드를 선언했다고 앱이 계속 실행되는 것은 아닙니다. 검색 이벤트가 합쳐지거나 연결 복구가 늦어질 수 있고, 프로세스가 종료되면 메모리의 연결 상태도 사라집니다.
따라서 차량 식별자, 마지막 단계와 진행 중인 요청 ID처럼 복구에 필요한 최소 상태를 저장해야 합니다. 앱이 다시 활성화되면 실제 Bluetooth 상태와 차량 응답을 재조회해 로컬 상태를 보정합니다.
사용자에게도 백그라운드 제약을 숨기지 않는 편이 좋습니다. 즉시 실행할 수 없는 명령은 대기 상태로 남기기보다 앱을 열어 차량 근처에서 다시 시도하도록 안내해야 합니다.
Pairing만으로 명령 권한이 완성되지는 않습니다
BLE Pairing과 Bonding은 링크 암호화와 기기 관계를 만드는 데 사용됩니다. 하지만 차량 제어 권한, 계정 변경과 키 폐기 정책까지 대신하지는 않습니다.
민감한 명령에는 애플리케이션 계층의 상호 인증, 짧은 유효 시간과 재전송 방지값이 필요합니다. 광고 데이터에 장기 비밀값을 넣거나 동일한 명령 바이트를 반복해서 허용해서는 안 됩니다. 차량과 앱은 세션별로 명령의 신선도를 검증하고 이미 처리한 요청 ID를 다시 실행하지 않아야 합니다.
RSSI도 인증 수단으로 사용하기 어렵습니다. 신호 세기는 휴대폰 방향, 차체, 주변 전파와 사람의 위치에 따라 크게 달라집니다. 가까운지 추정하는 보조 정보로 사용할 수는 있지만 특정 수치만으로 차량 접근 권한을 결정하면 오판 가능성이 큽니다.
저전력과 즉시 응답 사이의 기준을 정합니다
BLE 차량 제어는 항상 연결해 두는 방식과 필요할 때마다 처음부터 검색하는 방식 사이에서 균형을 잡는 문제입니다. 검색은 조건을 좁혀 짧게 끝내고, 연결은 명시적인 상태 기계로 관리하며, 명령 완료는 차량의 응답으로 확인해야 합니다.
전력 소비를 줄이는 설정은 응답 시간을 늘릴 수 있습니다. 중요한 것은 가장 낮은 소비량이 아니라 사용자가 기대하는 시간 안에 제어를 끝내면서 불필요한 무선 동작을 남기지 않는 것입니다.
함께 읽기
- 차량 상태 동기화: Push, WebSocket과 Polling을 함께 쓰는 이유커넥티드 카 앱의 차량 상태는 한 번 조회하고 끝나는 데이터가 아닙니다. 도어, 공조, 충전과 차량 온라인 상태는 앱 밖에서도 계속 바뀝니다. 사용자가 원격 명령을 실행하는 동안에도 이전 상태 이벤트와 새로운 조회 응답이 다른 순서로 도착할 수 있습니다.
- 커넥티드 카 원격 명령: 요청부터 차량 응답까지의 상태 관리커넥티드 카 앱에서 도어 잠금이나 공조 시작 버튼을 누르면 요청은 여러 시스템을 통과합니다. 앱이 서버 요청에 성공했다고 차량 기능까지 실행된 것은 아닙니다. 명령이 차량에 도착하고 제어 장치가 결과를 반환해야 비로소 실행 여부를 판단할 수 있습니다.
- 블록체인 트랜잭션을 만들고 서명해 전송하는 과정블록체인 지갑에서 전송 버튼을 누른 뒤 발생하는 일은 단순한 API 요청과 다릅니다. 앱은 사용자의 의도를 트랜잭션 데이터로 만들고, 현재 네트워크 상태에 맞춰 수수료와 nonce를 채우고, 개인키로 서명한 결과를 노드에 전파해야 합니다.
- 블록체인 지갑의 잔액과 토큰 내역을 동기화하는 구조블록체인 지갑의 잔액 화면은 서버 데이터베이스의 한 행을 읽어 보여 주는 화면이 아닙니다. 공개 주소를 기준으로 여러 블록체인 상태를 조회하고, 토큰 단위와 거래 확정 상태를 해석해 만든 하나의 읽기 모델입니다.
- 모바일 블록체인 지갑에서 개인키를 안전하게 관리하는 방법블록체인 지갑은 코인을 앱 내부에 보관하지 않습니다. 자산과 거래 기록은 블록체인에 남고, 지갑은 해당 자산을 움직일 수 있는 개인키를 관리합니다. 따라서 지갑 앱의 보안 경계는 화면 잠금이나 API 인증이 아니라 개인키가 생성되고 저장되고 사용되는 전체 과정에 놓입니다.