Insights·2026-07-31

테슬라를 코드로 제어할 수 있나 — Fleet API로 애프터블로우 자동화하기

가능하다. 테슬라는 Fleet API라는 공식 차량 제어 인터페이스를 열어 두었고, 차주가 자기 계정을 연결하면 프로그램이 문 잠금·트렁크·공조·충전·내비 목적지·센트리 모드까지 명령할 수 있다. 가장 실용적인 첫 자동화는 애프터블로우다. 차에서 내린 뒤 잠깐 바람을 돌려 에어컨 증발기를 말리는 동작인데, 여름 쉰내의 원인이 대부분 여기 남은 물기라 효과가 바로 체감되고, 정작 차량 메뉴에는 이 버튼이 없어서 이 기능 하나만 월 구독으로 파는 서비스가 따로 있을 정도다. 만드는 법은 단순하다. 도착하면 공조를 켜는 명령(auto_conditioning_start)과 온도를 올리는 명령(set_temps)을 부르고, 10분 뒤 끄는 명령(auto_conditioning_stop)을 부른다. 실제로 막히는 지점은 코드가 아니라 등록 절차다 — 개발자 앱 등록, 내 도메인의 정해진 경로에 공개키 올리기, 명령에 서명하는 프록시 실행 셋을 통과해야 한다. 이 절차야말로 Claude Code나 Codex 같은 코딩 에이전트에 그대로 맡기기 좋은 일이고, 비용은 계정마다 매달 붙는 10달러 크레딧 안에서 끝난다.

AI 에이전트 터미널, 테슬라 Fleet API 라이브 데이터 화면, 충전 중인 전기차를 나란히 놓은 구성
가운데 화면은 테슬라 개발자 사이트가 공개한 Fleet API Live Data 예시(developer.tesla.com)

테슬라를 코드로 제어한다는 게 무슨 뜻인가

API는 사람이 앱 화면을 누르는 대신 프로그램이 서비스에 말을 거는 창구다. 테슬라는 이 창구를 Fleet API라는 이름으로 공식 제공한다. 앱에서 누르던 문 잠금, 공조 켜기, 충전 시작 같은 동작이 각각 명령 이름으로 열려 있고, 프로그램이 그 이름을 호출하면 차가 실제로 움직인다.

예전에는 테슬라 앱의 통신을 뜯어본 비공식 API가 널리 쓰였지만 지금은 정식 경로가 따로 있다. 차주가 자기 테슬라 계정으로 로그인해 특정 앱에 권한을 위임하면(OAuth), 그 앱이 차주 대신 명령을 보낸다. 서드파티 서비스에 계정을 연결한다는 말이 바로 이 위임이다.

최근 차량은 여기에 한 겹이 더 붙는다. 명령에 전자 서명이 필요하고, 그 서명을 검증할 공개키를 차주가 차량에 직접 등록해야 한다. 이걸 virtual key라고 부른다. 차량의 잠금 화면에서 언제든 지울 수 있어서, 권한을 준 뒤에도 회수가 차주 손에 남는다.

정리하면 세 층이다. 차주 계정 위임(OAuth), 차량에 등록된 공개키(virtual key), 그리고 그 키로 명령에 서명하는 내 서버. 이 셋이 갖춰지면 그다음은 평범한 HTTP 요청이다.

무엇이 열려 있고 무엇은 안 열리나

열려 있는 명령의 범위는 생각보다 넓다. 아래는 테슬라가 공개한 명령 프록시 구현(teslamotors/vehicle-command)에 실제로 정의된 이름들을 분류한 것이다.

반대로 안 열리는 쪽도 분명하다. 조향·가감속 같은 주행 제어, 오토파일럿과 FSD 조작, 스마트 서먼, 카메라 영상과 센트리 클립 열람은 API에 없다. 문도 잠금 해제까지이고 물리적으로 여는 것은 아니다. 즉 'AI가 차를 운전한다'가 아니라 '차 주변의 반복 작업을 사람 대신 누른다'가 정확한 표현이다.

한 가지 더, 차가 잠들어 있으면 명령이 바로 먹지 않는다. wake_up으로 깨운 뒤 명령을 보내야 하는데 이 호출이 비싸다(비용 절 참고). 그래서 상태 확인을 반복하는 폴링 대신, 차가 알아서 서버로 신호를 보내는 Fleet Telemetry 스트리밍을 쓰는 편이 싸고 빠르다.

분류명령 이름(일부)
공조auto_conditioning_start · auto_conditioning_stop · set_temps · set_climate_keeper_mode · set_preconditioning_max · remote_seat_heater_request
문·수납door_lock · door_unlock · actuate_trunk(front/rear) · charge_port_door_open · window_control(vent/close)
충전charge_start · charge_stop · set_charge_limit · set_charging_amps · add_charge_schedule · add_precondition_schedule
보안·모드set_sentry_mode · set_valet_mode · guest_mode · speed_limit_activate · parental_controls_activate · set_pin_to_drive
편의navigation_request · trigger_homelink · flash_lights · honk_horn · set_vehicle_name · schedule_software_update · wake_up

왜 애프터블로우가 첫 자동화로 좋은가

애프터블로우는 주행을 마치고 내린 뒤 공조를 잠깐 더 돌려 에어컨 증발기(에바포레이터)를 말리는 동작이다. 냉방 중에는 증발기 표면에 공기 중 수분이 계속 맺히는데, 그 물기가 마르지 않은 채 남으면 곰팡이가 자라고 다음에 에어컨을 켤 때 쉰내로 돌아온다. 필터를 갈아도 냄새가 그대로인 경우가 많은 이유가 이것이다.

그런데 테슬라 차량 메뉴에는 애프터블로우 항목이 따로 없다. 그래서 이 기능만 대신 만들어 월 구독으로 파는 서비스가 실제로 있다. 텔레그램 봇 형태로 테슬라 계정을 연결하면 자연 건조와 열풍 건조를 대신 돌려 주고, 14일 무료 체험 뒤 월 1,000원부터 받는 식이다(가격은 sla-ai-bot.smartstream.kr 안내 기준).

첫 자동화로 좋은 이유는 셋이다. 첫째, 필요한 명령이 두세 개뿐이라 실패해도 위험이 없다. 둘째, 결과가 코로 확인된다 — 잘 됐는지 로그를 뒤질 필요가 없다. 셋째, 여기서 익힌 인증·서명·스케줄 구조가 충전 시간대 최적화, 출발 전 예열, 주차 후 자동 잠금 같은 다음 자동화에 그대로 재사용된다.

준비물 1 — 개발자 앱 등록과 공개키 호스팅

먼저 테슬라 개발자 사이트(developer.tesla.com)에서 애플리케이션을 등록한다. 개인이 자기 차만 쓰더라도 이 등록은 필요하다. 등록할 때 클라이언트 ID와 시크릿, 그리고 이 앱이 요구할 권한 범위(공조·충전·잠금 등)를 정한다.

여기서 초보자가 가장 많이 걸리는 지점이 도메인 요구사항이다. 앱마다 소유한 도메인 하나를 등록해야 하고, 그 도메인의 정해진 경로에 공개키 파일을 올려 두어야 한다. 경로는 고정이다 — /.well-known/appspecific/com.tesla.3p.public-key.pem. 테슬라가 이 주소로 직접 키를 읽어 가기 때문에, 로컬 파일이 아니라 인터넷에서 열리는 주소여야 한다.

키는 EC(prime256v1) 방식으로 만든다. 개인키는 내 서버에만 두고 절대 공개하지 않으며, 위 주소에 올리는 것은 공개키뿐이다. 개인키가 유출되면 그 키로 내 차에 명령을 보낼 수 있으니, 저장 위치와 권한을 처음부터 신경 써 둔다.

마지막으로 차주가 차량에 이 키를 등록한다. 앱이 안내하는 https://tesla.com/_ak/<내도메인> 링크를 차주가 휴대폰에서 열면 테슬라 앱이 뜨고, 승인하면 차량 화면에 키가 추가된다. 이때 차량은 온라인 상태여야 한다. 지우고 싶으면 차량의 잠금(Locks) 화면에서 해당 키를 삭제하면 끝이다.

터미널 — 키 만들고 공개키 올리기
# 1) 개인키 생성 (EC prime256v1) — 내 서버에만 보관
openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem

# 2) 공개키 추출
openssl ec -in private-key.pem -pubout -out public-key.pem

# 3) 내 도메인의 고정 경로에 공개키를 올린다 (경로는 바꿀 수 없다)
#    https://<내도메인>/.well-known/appspecific/com.tesla.3p.public-key.pem

# 4) 잘 열리는지 확인 — 브라우저로 봐도 된다
curl -s https://<내도메인>/.well-known/appspecific/com.tesla.3p.public-key.pem

# 5) 차주가 휴대폰에서 이 링크를 열어 차량에 키를 등록한다
#    https://tesla.com/_ak/<내도메인>

준비물 2 — 명령 서명 프록시 띄우기

최근 차량은 서명된 명령만 받는다. 서명을 직접 구현할 필요는 없다. 테슬라가 공식 오픈소스로 tesla-http-proxy를 내놓았고, 이걸 내 서버에 띄우면 평범한 HTTP 요청을 받아 개인키로 서명한 뒤 차에 전달해 준다. 즉 내 코드는 프록시에 curl 한 줄 던지는 수준으로 단순해진다.

설치는 Go로 하거나 도커 이미지를 받으면 된다. 함께 설치되는 도구가 넷이다. tesla-keygen은 명령 인증용 개인키를 만들어 시스템 키체인에 넣고, tesla-auth-token은 OAuth 토큰을 저장하며, tesla-control은 터미널에서 바로 명령을 보내 보는 시험용 도구, tesla-http-proxy가 지금 필요한 REST 프록시다.

프록시는 자기 자신도 TLS로 감싸서 뜬다. 그래서 실행할 때 프록시용 인증서와 키, 그리고 차량 명령 서명에 쓸 개인키 파일을 각각 넘긴다. 자체 서명 인증서를 쓰면 curl에 --cacert로 그 인증서를 알려 준다.

여기까지 되면 시험 삼아 라이트를 깜빡여 본다. 실패하면 원인은 대개 셋 중 하나다. 차가 잠들어 있거나(wake 필요), virtual key가 아직 차량에 등록되지 않았거나, 토큰 권한 범위에 해당 기능이 빠져 있는 경우다.

터미널 — 설치와 프록시 실행
# 설치 (둘 중 하나)
go install github.com/teslamotors/vehicle-command/cmd/...@latest   # Go 1.23+
docker pull tesla/vehicle-command:latest                            # 도커

# 키·토큰 이름과 차량 VIN을 환경변수로 잡아 둔다
export TESLA_KEY_NAME=$(whoami)
export TESLA_TOKEN_NAME=$(whoami)
export TESLA_CACHE_FILE=~/.tesla-cache.json
export TESLA_VIN=<내 차 VIN>

# 명령 인증용 개인키 생성 (공개키는 표준출력으로 나온다)
tesla-keygen create > public_key.pem

# REST 프록시 실행 — 4443 포트에서 대기
tesla-http-proxy -tls-key config/tls-key.pem -cert config/tls-cert.pem \
                 -key-file config/fleet-key.pem -port 4443
터미널 — 연결 확인(라이트 깜빡이기)
curl --cacert cert.pem \
     --header "Authorization: Bearer $TESLA_AUTH_TOKEN" \
     --data '{}' \
     "https://localhost:4443/api/1/vehicles/$TESLA_VIN/command/flash_lights"

애프터블로우 스크립트 만들기

이제 본론이다. 애프터블로우는 명령 세 번으로 끝난다. 공조를 켜고(auto_conditioning_start), 온도를 최대로 올리고(set_temps), 정해진 시간이 지나면 끈다(auto_conditioning_stop). 온도를 올리는 이유는 찬 바람이 아니라 따뜻한 바람으로 말려야 증발기가 실제로 마르기 때문이다.

시간은 10분 안팎이면 충분하다. 너무 길게 잡으면 주차장에서 계속 공조가 돌아 배터리를 쓴다. 처음에는 5분으로 시작해 냄새가 잡히는지 보고 늘리는 편이 낫다.

실행 시점은 두 가지 방법이 있다. 간단한 쪽은 하차 시각을 대략 아는 경우로, 스케줄러(cron이나 macOS launchd)에 시간을 박아 두는 것이다. 정확한 쪽은 Fleet Telemetry 스트리밍으로 주차 상태 신호를 받아, 차가 실제로 주차되면 스크립트를 부르는 방식이다. 폴링으로 상태를 계속 물어보는 방법은 wake 비용 때문에 권하지 않는다.

아래 스크립트는 프록시가 이미 떠 있다는 전제로 짠 최소 버전이다. 이 정도면 하드코딩된 값을 자기 환경에 맞게 바꾸는 것만으로 바로 돌아간다.

afterblow.sh — 공조 켜고 10분 뒤 끄기
#!/bin/bash
set -euo pipefail

PROXY="https://localhost:4443/api/1/vehicles/$TESLA_VIN/command"
AUTH="Authorization: Bearer $TESLA_AUTH_TOKEN"
CA="--cacert cert.pem"
DRY_MIN=10                     # 말리는 시간(분)

send() {  # send <명령이름> <JSON 본문>
  curl -s $CA --header "$AUTH" --header "Content-Type: application/json" \
       --data "$2" "$PROXY/$1"
  echo
}

# 잠들어 있으면 깨운다 (필요할 때만 — wake는 비싸다)
send wake_up '{}'
sleep 5

# 1) 공조 켜기  2) 운전석·조수석 온도 최대로
send auto_conditioning_start '{}'
send set_temps '{"driver_temp": 28, "passenger_temp": 28}'

# 3) 말리는 동안 대기 후 끄기
sleep $((DRY_MIN * 60))
send auto_conditioning_stop '{}'
crontab — 매일 저녁 퇴근 시각에 실행
# 평일 19시 10분에 애프터블로우 실행
10 19 * * 1-5 /Users/me/tesla/afterblow.sh >> /tmp/afterblow.log 2>&1

비용 — 개인이 쓰면 사실상 무료지만 함정이 둘 있다

Fleet API는 2025년 1월부터 사용량 과금이다. 그런데 계정마다 매달 10달러 크레딧이 붙어서, 차량 한두 대 자동화는 이 크레딧 안에서 끝난다. 테슬라가 든 예시가 차량 두 대 기준 스트리밍 + 하루 명령 100건 + wake 2회다. 애프터블로우는 하루 명령 서너 개니 여유가 크다.

첫 번째 함정은 결제수단이다. 크레딧 안에서만 쓰더라도 결제수단을 등록해 두지 않으면 앱이 자동으로 비활성화된다. 계정의 기본 지출 한도가 0이라, 결제수단을 등록해야 한도를 올릴 수 있는 구조이기도 하다. 반대로 한도를 낮게(예: 1~5달러) 걸어 두면 실수로 폭탄을 맞는 일도 막힌다.

두 번째 함정은 폴링이다. 명령은 싸지만 잠든 차를 깨우는 wake와 REST로 차량 상태를 계속 조회하는 호출이 비싸다. 1분마다 상태를 물어보는 루프를 짜면 크레딧이 며칠 만에 마른다. 상태가 필요하면 폴링 대신 Fleet Telemetry 스트리밍을 쓰는 것이 정석이다.

항목감각주의
월 크레딧계정당 10달러 자동 적용차량 1~2대 개인 자동화는 이 안에서 끝난다
명령1,000건에 1달러0.01달러 단위 반올림(1,211건이면 1.21달러)
wake명령의 약 20배필요할 때만 호출. 루프 안에 넣지 말 것
차량 데이터 폴링가장 비싼 축Fleet Telemetry 스트리밍으로 대체
결제수단미등록 시 앱 자동 비활성화지출 한도를 낮게 걸어 사고 방지

AI 코딩 에이전트에 무엇을 맡기나

여기까지 읽고 '절차가 많다'고 느꼈다면 정확한 감각이다. 실제로 어려운 건 코드가 아니라 등록·인증·서명이라는 부수 절차이고, 이런 일이야말로 Claude Code나 Codex 같은 코딩 에이전트가 잘하는 영역이다. 문서를 읽고, 명령을 실행하고, 결과를 보고 다음 단계를 고르는 반복이기 때문이다.

맡길 때는 목표가 아니라 확인 가능한 조건으로 지시하는 편이 결과가 좋다. '테슬라 자동화 만들어 줘'보다 '공개키가 이 주소에서 200으로 열리는지 확인하고, 프록시를 4443 포트에 띄운 다음 flash_lights가 성공하는 것까지 보여 줘'가 훨씬 낫다. 각 단계가 성공했는지 사람이 눈으로 판정할 수 있기 때문이다.

주의할 것 하나. 개인키와 액세스 토큰은 화면과 저장소에 남기지 않게 처음부터 규칙을 준다. 에이전트에게 키 파일 경로를 알려 주되 내용을 출력하지 말라고 하고, 환경변수와 .gitignore를 먼저 만들어 둔 뒤 작업을 시작하는 것이 안전하다.

에이전트에게 줄 지시 예시
1. https://github.com/teslamotors/vehicle-command 의 README를 읽고 설치해라.
2. openssl로 EC(prime256v1) 키쌍을 만들어라. 개인키는 ~/.tesla/ 아래에 두고
   내용은 절대 출력하지 마라. 경로만 알려라.
3. 공개키를 public/.well-known/appspecific/com.tesla.3p.public-key.pem 으로
   복사하고, 배포 후 그 주소가 200으로 열리는지 curl로 확인해라.
4. tesla-http-proxy를 4443 포트로 띄우고, flash_lights 명령이 성공하는 것까지
   보여 달라. 실패하면 원인이 wake·virtual key·scope 중 무엇인지 판별해라.
5. 마지막으로 afterblow.sh를 작성하고 crontab에 평일 19:10로 등록해라.
   토큰과 키는 .env로 분리하고 .gitignore에 넣어라.

정리 — 순서 체크리스트

하나, developer.tesla.com에서 앱을 등록하고 필요한 권한 범위를 고른다. 둘, EC 키쌍을 만들어 공개키를 내 도메인의 /.well-known/appspecific/com.tesla.3p.public-key.pem 에 올린다. 셋, https://tesla.com/_ak/<내도메인> 링크로 차량에 virtual key를 등록한다(차량 온라인 상태 필요).

넷, tesla-http-proxy를 띄우고 flash_lights로 연결을 확인한다. 다섯, afterblow.sh를 만들어 auto_conditioning_start → set_temps → 대기 → auto_conditioning_stop 순서를 넣는다. 여섯, 스케줄러에 등록하고 결제수단·지출 한도를 설정한다.

여기까지가 첫 자동화다. 같은 구조 위에 충전 시간대 최적화, 출발 전 예열, 주차 후 자동 잠금을 얹는 것은 명령 이름만 바꾸는 수준이다. 반대로 주행 제어와 FSD는 이 길로 열리지 않는다는 점은 처음부터 분명히 해 두는 편이 낫다.