6 분 소요

M7-6으로 충전기는 전원만 넣으면 뜨게 됐다. 하지만 사용자가 볼 화면이 없고, 카드로 인증할 방법도 없었다. 지금까지는 고정 카드 번호(SC6TEST01)로 꽂자마자 자동 인증했다. 이틀(11/12~13) 동안 이 두 가지를 붙였다.

일 결과
sc6-hmi: DWIN 모니터 ↔ EVerest 충전 상태에 따라 화면·음성 이동, 충전 중지 버튼, 시간 초과, 화면 보호, 커넥터 분리 화면 (r0.9)
sc6-rfid: 카드 리더 → EVerest 인증 리더 프레임 해석과 EVerest 전송 완성, PC 흉내로 시험 (실제 카드는 아직)
빌드 PC 주소 변경 .139 → .40 고정, 스크립트 51개 수정, SteVe 서버 인증서 다시 발급

1. sc6-hmi — 화면은 충전을 모른다

1-1. 구조: 화면 프로그램은 충전에 손대지 않는다

EVerest ── e2m/session_event (SessionStarted, ChargingStarted, ...) ──▶ sc6-hmi ── 화면 이동·음성 ──▶ DWIN (J8)
sc6-bsp ── 비상정지·누전 오류, CP 상태 (함께 들음)                   ──▶ sc6-hmi
DWIN 버튼 ──▶ sc6-hmi ── "충전 중지"면 m2e/stop_transaction ──▶ EVerest

sc6-hmi는 K1도 CP도 건드리지 않는다. 이 프로그램이 죽거나 모니터가 빠져도 충전과 안전에는 영향이 없다. EVerest에는 바깥 프로그램용 공개 API(evse_manager_consumer_API)가 있어, 구성 파일에 모듈 하나를 추가하면 충전 상태가 MQTT로 나온다.

모니터는 DWIN T5L(DGUS II)이다. 처음에는 옛 DGUS 명령으로 화면을 옮기려다 실패했다. 이 모니터는 DGUS II 방식으로만 움직였다.

화면 이동  5A A5 07 82 00 84 5A 01 <화면 번호 2바이트>
음성 재생  5A A5 07 82 00 A0 <음성 번호> 01 <볼륨> 00

음성 파일 17개는 이름이 번호뿐이라, Whisper로 받아 적어 번호표를 만들었다(1 “신용카드를 접촉해주세요” … 17 “시작 버튼을 눌러주세요”).

1-2. 화면 번호는 코드에 넣지 않는다

화면 번호는 모니터에 넣는 UI 판마다 다르다. 그래서 코드에는 상태만 두고, 상태마다 갈 화면과 음성은 설정 파일에 둔다.

# /etc/default/sc6-hmi
PAGE_MAIN=1        SOUND_MAIN=17
PAGE_PREPARE=7     SOUND_PREPARE=4
PAGE_CHARGING=8    SOUND_CHARGING=5
PAGE_FINISHED=9    SOUND_FINISHED=3
PAGE_UNPLUG=10     SOUND_UNPLUG=7
BUTTON_PAGE_1=6    # 버튼 1 -> 6페이지 (화면만)
BUTTON_STATE_1=PLUG  # 또는 상태를 바꿈 (그 상태의 화면·음성)

화면 설계는 사람이 직접 하고, 프로그램은 그 구조만 제공한다. 실제로 오늘 커넥터 분리 화면(UNPLUG 상태)은 코드부터 직접 고쳐서 넣었다.

1-3. 꽂자마자 “충전 중” 화면이 떴다

지그를 B(차 연결)로 바꾸자마자 화면이 충전 중(8페이지)으로 갔다. 차는 아직 전기를 달라고(C) 하지 않았다.

원인은 sc6-hmi가 TransactionStarted(거래 시작)를 충전 중으로 본 것이다. 지금 구성은 고정 카드로 꽂자마자 자동 인증하므로, CP B만 돼도 거래가 시작된다. 실제로 전기가 나가는 것은 차가 C로 바꾸고 K1이 붙을 때 오는 ChargingStarted다.

이벤트 뜻 화면
SessionStarted 커넥터 연결 (CP B) 준비
TransactionStarted 인증 끝, 거래 시작 준비 그대로
ChargingStarted CP C + K1 ON 충전 중
TransactionFinished 거래 끝 결과
SessionFinished 커넥터 분리 메인

1-4. 시간 초과는 “어디서” 거는지가 핵심

처음에는 “모든 화면에서 시간이 지나면 메인으로”였다. 그런데 메뉴 화면에서 60초를 기다려도 메인으로 돌아오지 않았다. 버튼으로 화면만 옮기면(BUTTON_PAGE) 상태는 MAIN 그대로였기 때문이다. 반대로 충전 중, 결과, 커넥터 분리 화면은 시간이 지나도 메인으로 가면 안 된다는 요구가 나왔다.

화면 시간 초과로 메인
메인에서 버튼으로 옮긴 화면, 커넥터 연결 대기 간다
준비 (인증 기다림) 간다
준비 (거래 시작 뒤, 차가 C로 가기를 기다림) 안 간다 — 꽂힌 채 메인 화면이 되면 안 됨
충전 중, 결과, 커넥터 분리, 경보 안 간다
NO_TIMEOUT_PAGES에 적은 화면 안 간다

버튼을 누를 때마다 시간은 처음부터 다시 센다. 메인 화면에서 오래 아무 일이 없으면 화면 보호 화면으로 가고, 아무 버튼이나 누르면 깨운다.

1-5. 설정 한 줄이 코드보다 빨랐다

  • 재부팅 뒤 화면이 안 바뀐다: “EVerest 신호가 안 온다”고 의심했다. 실제로는 sc6-hmi가 아직 서비스가 아니라 재부팅 뒤 실행되지 않았을 뿐이었다.
  • 시작할 때 음성이 두 번 났다: 시작 상태와 메인 상태에 같은 음성을 넣었기 때문이다. 이 덕에 “EVerest 연결 → 메인” 전환이 실제로 된다는 것도 확인됐다.

1-6. enum과 이름 배열은 같이 고친다

UNPLUG 상태를 넣을 때 enum에만 추가하면, 이름 배열이 한 칸씩 밀린다. 마지막 칸은 NULL이 되어 설정 파일을 읽다가 죽는다. 순서를 바꿔 넣으면 죽지는 않지만 PAGE_FINISHED와 PAGE_UNPLUG가 서로 바뀌어 붙는다. 빌드 전에 diff를 보고 잡았다.


2. 하룻밤 사이 빌드 PC 주소가 바뀌었다

아침에 빌드 PC로 SSH가 안 됐다. ping은 되는데 22번 포트는 Connection refused였다. SSH를 다시 켜도 같았다. 알고 보니 빌드 PC는 DHCP로 .40을 새로 받았고, 옛 주소 .139는 다른 장비가 쓰고 있었다. ping에 답한 것은 엉뚱한 장비였다.

  1. 같은 PC인지 확인: .40의 SSH 호스트 키가 known_hosts에 있던 .139의 키와 세 종류 모두 같았다.
  2. .40 고정: NetworkManager에서 manual로 고정했다. PC에만 고정하면 꺼져 있는 동안 공유기가 그 주소를 남에게 줄 수 있으니, 공유기 예약이나 DHCP 범위 밖 주소가 함께 필요하다.
  3. 주소 바꾸기: 지금 쓰는 스크립트 40여 개와 충전기 OCPP 설정을 바꿨다(51개 파일). 지난 기록(archive, 블로그)은 그날의 기록이라 그대로 뒀다.
  4. 서버 인증서: 보안 프로파일 2에서 만든 SteVe 서버 인증서는 SAN이 .139였다. 주소만 바꾸면 보드가 TLS 검증에서 끊는다. 기존 시험 CA로 서버 인증서만 다시 발급했다. 그래서 보드의 CA 파일과 충전기 비밀번호는 바꾸지 않아도 됐다.

보드 설정의 주소를 바꾸자 바로 붙었다. 끊겨 있던 동안 쌓인 MeterValues와 부팅 기록 3건이 연결 직후 한꺼번에 서버로 갔다.


3. sc6-rfid — 카드 리더를 EVerest 인증에 붙이다

3-1. 리더와 보드

인증은 1차로 RFID 회원카드(교통카드 CSN)로 하기로 했다. 리더는 3ALogics TNM-100이다.

  • 5V, RS-232 9600 8N1, 4핀. 보드 J9(UART8, /dev/ttySTM2)와 핀 번호가 1:1로 맞는다.
  • 카드를 대면 리더가 먼저 프레임을 보낸다. 형식은 시작 바이트, 길이, 데이터, XOR 체크섬(LRC)이다.
  • 데이터는 카드 종류 글자(T 티머니, C 캐시비, R 레일플러스)와 카드 ID 8바이트다.

3-2. RealTerm 흉내 — “02”는 1바이트가 아니라 2글자였다

실제 리더를 붙이기 전에 PC 시리얼 프로그램으로 리더를 흉내 냈다. 첫 결과는 “프레임 없음”이었다.

30 32 20 30 30 20 30 39 20 35 34 ... 0d 0a
 0  2 ␣  0  0 ␣  0  9 ␣  5  4 ... CR LF

PC 프로그램이 HEX를 글자로 보내고 있었다. RealTerm에서는 Send Numbers로 보내야 바이트로 나가고, +CR/+LF도 꺼야 한다. 그 뒤 16번 보내서 16번 모두 LRC OK로 받았다. 데이터를 바꾸면서 LRC를 그대로 두었더니 프레임을 버렸다. 이것도 의도한 동작이다.

3-3. EVerest 쪽은 공개 API 하나

EVerest에는 바깥 프로그램이 카드 번호를 넣는 auth_token_provider_API가 있다. sc6-meter가 powermeter_API를 쓰는 것과 같은 방식이다.

everest_api/1/auth_token_provider/rfid_1/m2e/provided_token
{"id_token":{"value":"1122334455667788","type":"ISO14443"},"authorization_type":"RFID"}

EVerest Auth가 이 번호를 OCPP Authorize로 서버에 확인하고 충전을 허가한다. sc6-rfid가 하는 일은 다음과 같다.

  • 바이트 단위 상태 기계로 프레임을 받는다. 쓰레기 바이트나 LRC 틀린 프레임은 버린다.
  • 카드를 대고 있는 동안 리더가 같은 번호를 되풀이하면, 정한 시간 안에는 한 번만 보낸다.
  • 주기적으로 리더에 살아 있는지 묻는다. 답이 끊기면 EVerest에 통신 확인(communication_check)을 멈춰 알린다.
  • 카드 ID를 16진수 16자로 쓸지 글자 8자로 쓸지는 설정으로 고른다(ID_FORMAT). 실제 카드의 ID 형식을 아직 모르기 때문이다. OCPP 1.6 idTag는 20자까지라 둘 다 들어간다.

WSL과 빌드 PC에는 libmosquitto 개발 헤더가 없었다. 그래서 MQTT로 보낼 내용을 화면에 찍기만 하는 대체 파일을 만들어 컴파일했고, 가짜 리더(pty)를 붙여 시험했다. 같은 카드 무시, 쓰레기 바이트, LRC 오류, 한 바이트씩 끊어 들어온 프레임, 리더 무응답까지 모두 확인했다.


4. 정리

커밋

meta-sc6  f40d6bc  sc6-hmi: DWIN 모니터(J8) <-> EVerest 연동 뼈대
meta-sc6  a9591f2  sc6-hmi: 버튼 화면 이동, PLUG 상태, CP 상태 수신 (r0.5)
meta-sc6  7b9f487  sc6-hmi: 충전 상태 판정, 시간 초과·화면 보호, 커넥터 분리 화면 (r0.9)
meta-sc6  bcf78c8  sc6-everest-config: OCPP 서버 주소 192.168.45.40
sc6-work  aa1e9e2  빌드 PC 주소 192.168.45.139 -> 192.168.45.40
sc6-work  ebe95ef  sc6-hmi 보드 시험 스크립트 (test-hmi.sh)
(sc6-rfid, test-rfid.sh 는 이 글과 함께 커밋)

배운 것

  1. “거래 시작”과 “충전 시작”은 다르다. 자동 인증 구성에서는 꽂는 순간 거래가 시작된다. 화면은 전기가 실제로 나가는 이벤트를 봐야 한다.
  2. 시간 초과는 전역 규칙이 아니라 화면마다 정하는 것이다. 메인으로 돌아가면 안 되는 화면(충전 중, 결과, 분리 안내)이 먼저 정해져야 한다.
  3. ping이 된다고 그 장비가 맞는 것은 아니다. 호스트 키를 비교해서 같은 PC인지 확인했다.
  4. 인증서는 주소에 묶여 있다. CA를 그대로 두고 서버 인증서만 다시 발급하면 충전기 쪽은 손대지 않아도 된다.
  5. 흉내 도구도 설정이 반이다. “글자로 보낸 HEX”는 사람이 보기엔 같아도 기계에게는 전혀 다른 데이터다.

남은 것

항목 내용
sc6-hmi 보드 시험 충전 중지 버튼의 stop_transaction 응답 형식 첫 확인, 결과 → 분리 → 메인 흐름
sc6-rfid 보드 시험, 실제 TNM-100과 카드로 ID 형식 확인
EVerest 구성 DummyTokenProvider를 auth_token_provider_API(rfid_1)로 교체, SteVe에 카드 등록
sc6-hmi 인증 화면 AUTH 상태(카드 접촉 안내), 거절 화면
이미지 sc6-hmi, sc6-rfid 서비스를 이미지에 넣기
정책 오프라인 인증, 비상정지 해제 방식 (설계자 확인)

댓글남기기