콘텐츠로 이동

LoRaWAN (ChirpStack)~

AoT는 ChirpStack v4 네트워크 서버를 통해 LoRaWAN 장치와 연결합니다. 업링크는 ChirpStack MQTT 브로커로 들어와 입력의 측정값이 되고, 다운링크는 출력이 ChirpStack API로 큐에 넣습니다. 두 모듈 모두 기본 내장입니다.

접속 설정은 설정 → ChirpStack 에서 한 번만 하고, 같은 화면에서 ChirpStack에 이미 등록된 장치를 골라 DevEUI와 키를 다시 입력하지 않고 AoT의 입력·출력으로 등록합니다.

AoT가 하지 않는 일~

AoT는 LoRaWAN 네트워크 서버가 아니고 게이트웨이 관리 도구도 아닙니다. ChirpStack의 클라이언트입니다.

다음은 전부 ChirpStack 쪽 일이며 AoT에 대응하는 화면이 없습니다.

  • 게이트웨이 등록과 지역(채널 플랜) 설정
  • 테넌트·애플리케이션·장치 프로파일·장치 생성(DevEUI, AppKey, 조인)
  • RX2 데이터레이트 — 다운링크 페이싱에서 설명하듯 AoT의 전송 간격이 여기에 맞춰집니다
  • 장치 프로파일이 Class C를 허용하는지 여부

그래서 순서는 언제나 이렇습니다. 먼저 ChirpStack에서 장치를 조인시켜 업링크가 들어오게 한 뒤, AoT로 가져옵니다. 한 번도 조인하지 않은 장치는 AoT에서 아무리 해도 나타나지 않습니다.

AoT와 ChirpStack 연결~

1. API 키 저장~

ChirpStack API 키는 ChirpStack 화면에 직접 입력하지 않습니다. 설정 → API 키 관리의 키 저장소에 넣고, ChirpStack 화면에서는 어떤 키를 쓸지 고르기만 합니다. 먼저 키를 등록하십시오.

항목 설명
이름 원하는 이름. ChirpStack 화면의 선택 목록에 이 이름이 표시됩니다
제공자/제조사 선택 사항. 선택 목록에서 이름 뒤 괄호로 표시됩니다
API 키 ChirpStack이 발급한 키 값. 토큰 본문만 붙여 넣습니다

Bearer 접두어 없이 붙여 넣으십시오. 접두어가 있어도 사용 전에 제거되지만, 값 자체를 깨끗하게 두는 편이 다른 화면에서 혼동을 줄입니다.

키의 권한이 AoT가 볼 수 있는 범위를 정합니다. 관리자 키는 테넌트를 열거할 수 있어 그 아래 모든 애플리케이션이 보입니다. 테넌트 범위 키는 테넌트를 나열하지 못하는데, AoT가 이를 감지해 테넌트 필터 없이 애플리케이션을 나열하는 방식으로 대체하므로 그런 키로도 동작합니다 — 다만 목록의 테넌트 칸이 비어 보입니다.

2. 접속 정보 입력~

설정 → ChirpStack 으로 갑니다.

항목 설명
ChirpStack gRPC 서버 ChirpStack API의 호스트:포트. 포트를 생략하면 :8080이 붙습니다
API 토큰 저장된 API 키 중 하나를 고릅니다. API 키 관리 버튼으로 저장소로 이동합니다
MQTT 브로커 호스트 ChirpStack이 이벤트를 발행하는 브로커의 호스트
MQTT 브로커 포트 보통 1883

저장을 누릅니다. 새로 고침은 설정을 바꾸지 않고 장치 목록만 다시 읽습니다.

서버 칸의 스킴(http://, https://)과 뒤에 붙은 경로는 무시하고 호스트와 포트만 씁니다. 포트가 8080이 아니면 반드시 적으십시오. 포트가 없으면 닿을 수 없는 주소로 해석돼, 인증 오류나 접속 오류 대신 "네트워크에 도달할 수 없음" 같은 엉뚱한 메시지가 나옵니다.

서로 다른 두 경로입니다

gRPC 서버 주소는 다운링크와 장치 목록 조회에, MQTT 브로커는 업링크에 씁니다. 별개의 서비스이고 같은 호스트의 다른 포트인 경우가 많아서, 장치 목록이 잘 나온다고 업링크가 들어온다는 뜻은 아니고 그 반대도 마찬가지입니다.

gRPC 클라이언트 라이브러리가 없으면 화면 위에 안내가 뜨고 장치 목록이 비어 있게 됩니다. AoT 요구 패키지에 포함돼 있으므로 보통은 직접 구성한 환경에서만 나타납니다.

3. 장치 목록 확인~

접속을 저장하면 키로 접근 가능한 모든 장치가 테넌트 → 애플리케이션 → 이름 순으로 나열되고, 테넌트·애플리케이션 드롭다운으로 범위를 좁힐 수 있습니다. 각 행의 상세 버튼은 DevEUI, 테넌트, 애플리케이션, 마지막 수신 시각과 함께 그 장치가 이미 AoT의 입력·출력으로 등록돼 있는지를 보여 줍니다.

"장치를 찾을 수 없다"는 안내는 키로 ChirpStack에는 닿았지만 볼 장치가 없다는 뜻입니다 — 장치는 ChirpStack에 먼저 있어야 여기 나옵니다. 반면 오류 메시지가 나오면 접속이나 키 자체가 실패한 것입니다.

장치 등록~

장치 온보딩 영역은 장치 목록이 채워졌을 때만 나타납니다. 아래 표에서 원하는 장치를 체크한 뒤 무엇을 만들지 고릅니다.

입력(업링크)입력 등록을 켜면 선택한 장치마다 ChirpStack MQTT 입력이 하나씩 생깁니다. 채널 칸에는 한 줄에 JMESPath 하나를 적고, 줄 수가 곧 측정 채널 수가 됩니다. 같은 장치 프로파일을 쓰는 장치는 페이로드 구조가 같으므로, 대개 같은 표현식 묶음을 여러 장치에 한 번에 적용할 수 있습니다. 예:

object.battery_V
object.node_class
rxInfo[0].rssi
rxInfo[0].snr

출력(다운링크)출력 등록을 켜면 선택한 장치마다 ChirpStack 다운링크 출력이 하나씩 생깁니다. 장치 프로파일에 공통인 값을 적으십시오 — On 페이로드Off 페이로드(16진, 예 010110 / 010210), 그리고 펌웨어가 명령을 받는 FPort.

그다음 선택한 장치 등록을 누릅니다. AoT가 장치마다 DevEUI·브로커 주소·서버·키를 채워 넣은 모듈을 만들어 주므로 장치별로 다시 입력할 것이 없습니다. 여기서 만들어진 것은 평범한 입력·출력이므로 입력·출력에서 이름을 바꾸거나 채널·페이로드를 수정하면 됩니다.

접속 정보는 참조가 아니라 복사됩니다

등록 시점의 MQTT 호스트·포트가 각 입력에, gRPC 서버와 API 키가 각 출력에 복사됩니다. 스냅샷입니다. 나중에 ChirpStack 설정 화면에서 서버 주소를 바꾸거나 API 키를 교체해도 이미 등록된 입력·출력은 옛 값을 그대로 씁니다 — 하나씩 고쳐야 합니다. 예외는 출력의 확인 응답 수신용 MQTT 브로커뿐으로, 이것만 설정에서 그때그때 읽습니다.

같은 장치를 두 번 등록하면 기존 것이 갱신되는 게 아니라 두 번째 모듈이 새로 생깁니다. 장치 상세의 "등록됨" 줄로 이미 있는 것을 먼저 확인하십시오.

온보딩이 만드는 입력은 ChirpStack: MQTT (Payload JMESPath Expression) 입니다. ChirpStack v4의 업링크 토픽 application/+/device/+/event/up 을 구독하고, 들어온 이벤트 JSON에 채널별 JMESPath를 하나씩 적용합니다.

옵션 설명
MQTT 호스트 / 포트 브로커 주소. 등록 시 ChirpStack 설정에서 채워집니다
MQTT 사용자 / 비밀번호 선택 사항인 브로커 인증
TLS 사용 / CA 인증서 경로 선택 사항. TLS는 보통 8883 포트
구독 토픽 쉼표 구분. 기본값은 ChirpStack v4 업링크 토픽
Device EUIs 쉼표 구분 필터. 온보딩은 해당 장치 하나로 설정합니다
QoS, Keepalive, Client ID 일반적인 MQTT 설정

채널마다 있는 것은 이름과 JMESPath 표현식뿐이고, 표현식은 이벤트 전체를 대상으로 평가됩니다. 자주 쓰는 예:

표현식
object.battery_V 디코딩된 필드 — ChirpStack 코덱이 object 아래에 만들어 준 값
max_by(rxInfo,&rssi).rssi 이 업링크의 최적 게이트웨이 RSSI
max_by(rxInfo,&snr).snr 최적 게이트웨이 SNR

값이 저장되는 방식에서 알아 둘 점:

  • 표현식 결과는 숫자로 변환 가능해야 합니다. 결과가 null이면 그 채널에는 아무것도 저장하지 않으며 오류도 아닙니다 — 어떤 업링크에는 없는 필드를 이렇게 처리합니다.
  • 컴파일에 실패한 표현식은 해당 채널을 비활성으로 두고 시작 시 로그에 남깁니다. 오타는 데이터가 조용히 비는 대신 로그로 드러납니다.
  • 측정 시각은 수신 시각이 아니라 업링크 자신의 time 필드를 씁니다.
  • 활성화할 측정값 선택에서 꺼 둔 채널은 저장 직전에 버립니다. 밀려 들어오는 측정값에도 적용되므로, 채널을 끄면 실제로 기록이 멈춥니다.
  • 이 입력은 리스너 방식입니다. 주기는 폴링 간격이 아니며, 정해진 시각에 무언가를 가져오지 않습니다.

이 입력의 통신 상태는 장치가 아니라 브로커 연결을 기준으로 판정합니다. 업링크가 오면 장치가 살아 있다는 증거지만, 조용하다고 죽었다는 증거는 아니기 때문입니다 — 보고할 것이 없어서 조용할 수도 있습니다. 일정 시간 침묵하면 두절로 보고 싶다면 측정값 나이를 기준으로 함수에서 직접 구성하십시오.

MQTT 경로로 해결되지 않는 경우를 위한 입력이 둘 더 있습니다.

  • ChirpStack: REST API (Payload JMESPath Expression) 는 구독 대신 주기마다 ChirpStack REST API를 폴링합니다. AoT에서 브로커에 닿을 수 없을 때 씁니다. 자체 API 기본 URL(REST 프록시는 보통 8090 포트)과 토큰이 필요합니다.
  • RAK3172 Valve Controller: Heartbeat (ChirpStack MQTT) 는 그 펌웨어의 FPort 225 하트비트를 JMESPath 없이 바로 디코딩합니다 — 배터리, 노드 클래스, 하트비트 주기, 밸브 상태, RSSI/SNR.

온보딩이 만드는 출력은 On/Off: ChirpStack gRPC 입니다. 채널을 켜거나 끄면 그 장치에 다운링크가 큐에 들어갑니다.

옵션 설명
ChirpStack gRPC 서버 / API 키 등록 시 설정 화면에서 복사됩니다
DevEUI 대상 장치
FPort 펌웨어가 명령을 받는 포트
페이로드 형식 Hex Bytes 또는 JSON Object
On 페이로드 / Off 페이로드 보낼 프레임
Confirmed LoRaWAN confirmed 다운링크로 요청
명령 시한(초) 장치 응답을 기다리는 동안 명령한 상태를 낙관적으로 유지하는 시간. 이 모듈은 8로 채워집니다
디버그 로깅 접속·전송 알림을 로그로 남깁니다. 평상시에는 꺼 두십시오

AoT는 gRPC를 먼저 시도하고, gRPC 클라이언트가 없거나 호출이 실패하면 REST 큐 엔드포인트로 대체합니다(gRPC가 8080이면 8090도 시도). 어느 쪽이든 프레임은 그 장치의 ChirpStack 큐에 들어갑니다.

큐에 들어간 것과 전달된 것은 다릅니다. Class C 장치는 언제든 받을 수 있지만, Class A 장치는 다음 업링크 뒤에 열리는 수신창에서만 받으므로 하트비트 주기가 길면 명령이 큐에서 오래 기다립니다. Class C 허용 여부는 ChirpStack의 장치 프로파일 속성이며, AoT가 이를 어떻게 다루는지는 클래스 스케줄링을 보십시오.

확인 응답~

이 출력은 프레임을 큐에 넣었다는 이유만으로 장치가 동작했다고 보지 않습니다. 해당 DevEUI의 업링크 토픽을 MQTT로 구독해 펌웨어의 확인·상태 프레임을 기다립니다. 그래서:

  • 장치 보고가 오기 전까지 채널은 켜짐이 아니라 대기 중입니다. 시간 지정 명령의 동작 시간은 장치가 응답한 시점부터 셉니다 — 전송 지연이 켜져 있던 시간에 섞이지 않습니다.
  • ChirpStack v4는 응답 없는 다운링크를 스스로 재전송하지 않으므로, AoT가 시한 안에서 같은 명령을 재전송합니다. 재전송 간격은 명령 시한의 1/3이되 페이싱 간격보다 짧아지지 않습니다 — 물리적으로 더 일찍 나갈 수 없는 재전송은 대기만 하다가 시한을 넘기기 때문입니다.
  • 시한이 끝날 때까지 확인이 없으면 명령은 실패로 보고되고 채널은 명령 이전 상태로 돌아갑니다. 장치가 확인해 준 적 없는 상태를 계속 표시하지 않습니다.
  • 확인 없이 포기한 채널은 두절로 간주해, 이후 명령은 재전송 없이 한 번만 탐침으로 나갑니다. 없는 장치가 사이트 전체의 다운링크 여유를 잠식하지 못하게 하기 위함이며, 확인이 한 번 오면 정상으로 돌아갑니다.

이 리스너가 쓰는 브로커는 설정 → ChirpStack 에서 그때그때 읽습니다. 그래서 입력의 업링크는 잘 들어오는데 확인 응답만 안 온다면 브로커가 원인인 경우는 드뭅니다.

다운링크 페이싱~

AoT의 모든 다운링크는 — 출력에서 나가는 것, 클래스 스케줄러가 보내는 것, 모든 재전송까지 — 사이트 단위 하나의 속도 제한기를 지납니다. 부하가 걸릴 때 LoRaWAN 사이트가 이상해지는 현상을 이해하는 데 가장 중요한 부분입니다.

왜 있는가. 사이트에는 보통 게이트웨이가 하나뿐이고, 게이트웨이는 반이중입니다 — 송신 중에는 아무것도 듣지 못합니다. Class C 다운링크는 RX2로 나가는데, RX2 데이터레이트가 낮으면 작은 프레임 하나가 1초 넘게 전파를 차지합니다. 명령을 연달아 밀어 넣으면 게이트웨이가 1분의 대부분을 귀먹은 채로 보내고, 하필 그때가 장치들이 재전송 로직이 기다리는 확인 응답을 보내는 시각입니다. 확인을 놓치면 재전송이 늘고, 재전송은 송신 시간을 늘리고, 그래서 더 많은 확인을 놓칩니다. 현장에서 실제로 이 붕괴가 측정됐고, 5초 내 응답률이 61%까지 떨어졌습니다.

어떻게 동작하는가. 사이트 전체에서 어떤 두 다운링크 사이에도 최소 간격을 강제하고, 자기 차례까지 30초를 넘게 기다려야 하는 전송은 늦게 보내는 대신 버리고 실패로 보고합니다. 30초를 기다린 밸브 명령은 이미 낡았고, 밀린 것을 한꺼번에 풀면 페이싱이 막으려던 바로 그 홍수가 재현되기 때문입니다.

간격은 RX2 데이터레이트에 묶여 있고, 둘은 함께 움직여야 합니다. 이 간격은 설정 항목이 아니라 내장 상수이므로, 다른 RX2 데이터레이트에 맞추는 것은 설정 변경이 아니라 코드 변경입니다.

ChirpStack RX2 데이터레이트 프레임당 대략적 전파 점유 맞는 간격
rx2_dr = 0 (SF12) 약 1.32초 4.0초
rx2_dr = 2 (SF10) 약 0.37초 1.5초 — 현재 AoT 값
rx2_dr = 3 (SF9) 약 0.19초 0.8초

피해야 할 조합은 이것입니다. ChirpStack의 RX2를 SF12로 둔 채 AoT는 SF10 기준으로 페이싱하는 것. 그러면 송신 하나가 간격의 대부분을 차지해 게이트웨이가 사실상 내내 귀먹고, 위에서 말한 붕괴가 그대로 돌아옵니다. RX2 데이터레이트만 올리고 간격을 줄이지 않는 것은 그저 보수적일 뿐이지만, 간격만 줄이고 데이터레이트를 올리지 않는 것은 안전하지 않습니다.

페이싱의 영향이 다른 곳에 보이는 경우가 둘 있는데, 둘 다 고장이 아닙니다.

  • LoRaWAN 출력을 여러 개 활성화하거나 다시 적재할 때 시간이 걸립니다. 시작 상태 프레임도 페이싱을 타기 때문입니다. AoT는 데몬이 빨리 뜨도록 이 전송을 백그라운드로 미룹니다.
  • 출력 설정을 저장할 때는 종료 상태·시작 상태 프레임을 보내지 않습니다. 밸브 이름만 바꿔 저장했는데 다운링크 2건을 쓰고 밸브가 실제로 움직이는 일을 막기 위함입니다. 출력을 삭제할 때는 종료 상태를 적용해 장치를 안전한 상태로 둡니다.

클래스 스케줄링~

Class C는 장치를 언제든 부를 수 있게 해 주지만 수신기를 계속 켜 두므로 전력을 씁니다. 배터리·태양광 노드를 하루 종일 Class C로 두는 것은 대개 손해입니다. LoRaWAN 클래스 스케줄러 함수가 그 판단을 맡는 사이트 단위 단일 주체입니다 — 공유 ChirpStack 장치 프로파일의 Class C 허용을 켜고 끄면서 장치에는 대응하는 하트비트 모드를 함께 내려보내, 클래스와 하트비트 주기가 장치별로 어긋나지 않게 합니다.

주요 설정:

설정 설명
제어 모드 AUTO는 환경 입력을 점수화, MANUAL은 매일 고정된 Class C 구간
Manual C 시작 / 종료 MANUAL 모드의 일일 구간
점수 임계값, 최소 유지 시간 AUTO에서 활성 상태로 들어가고 나가는 기준과, 최소로 머무는 시간
클래스 / 하트비트 주기 활성·휴지·겨울 상태의 하트비트 간격
겨울 시작 / 종료 강제로 휴지 상태로 두는 날짜 구간
배터리 종류 배터리 게이트를 켭니다 — 전력이 부족한 노드는 Class C로 올리지 않습니다
REST 포트 ChirpStack REST 포트, 기본 8090. 서버와 키는 ChirpStack 설정에서 가져옵니다

지정한 분 동안 활성 상태를 강제하는 버튼과 그 강제를 해제하는 버튼이 있습니다. 스케줄러 자체에는 측정 설정이 없습니다 — 텔레메트리 채널은 장치가 배정될 때 만들어집니다.

장치마다 하나씩 두던 LoRaWAN Mode/Period Manager (RAK3172E) 함수도 아직 있고 동작하지만, 사이트 단위 스케줄러가 이를 대체합니다. 장치마다 관리자를 두기보다 여러 장치가 스케줄러 하나를 공유하는 쪽을 쓰십시오.

노드를 장치 하나로 추가하기~

센서이면서 동시에 구동기인 노드는 입력과 출력을 따로 등록하면 DevEUI만 같은 항목 두 개를 관리하게 됩니다. 장치 페이지에는 접속 정보 한 벌로 그 쌍을 만들어 주는 복합 장치 종류가 있습니다 — ChirpStack 릴레이 노드라면 AoT-C (Solar 12V Relay Node) 입니다. DevEUI, MQTT 브로커, gRPC 서버와 키를 한 번만 넣으면 텔레메트리 입력과 다운링크 출력이 함께 만들어지고 그 값들과 계속 맞춰집니다.

Class Scheduler 칸은 이 DevEUI를 관리할 기존 LoRaWAN 클래스 스케줄러를 고르는 자리입니다. 스케줄러를 새로 만들지 않습니다 — 여러 장치가 하나를 공유하는 것이 목적입니다. 클래스를 직접 관리하려면 비워 두십시오.

문제 해결~

위에서부터 순서대로 확인하십시오. 각 단계는 그 위 단계가 통과했다고 전제합니다.

장치 목록이 비어 있거나 오류가 납니다.

  1. ChirpStack 자체 화면에서 장치가 실제로 있는지 확인합니다.
  2. gRPC 서버 칸의 호스트와 포트를 확인합니다. 8080이 아니면 포트를 반드시 적습니다. 스킴과 경로는 무시되므로 원인이 아닙니다.
  3. 고른 API 키의 값이 ChirpStack 토큰이 맞는지 확인합니다. 선택 목록에는 키 이름만 보이므로 다른 키를 고르기 쉽습니다.
  4. 특정 테넌트의 장치만 안 보이면 키가 다른 테넌트로 한정된 것입니다. 관리자 키는 전부 봅니다.
  5. gRPC 클라이언트 라이브러리가 없다는 안내가 뜨면 환경이 불완전한 것입니다 — 의존성을 보십시오.

ChirpStack에는 업링크가 보이는데 AoT로 안 들어옵니다.

  1. 장치 목록은 gRPC, 업링크는 MQTT입니다. MQTT 브로커 호스트·포트를 따로 확인하고, AoT가 그 브로커에 닿을 수 있는지 확인합니다(컨테이너에서는 브라우저에서 쓰는 호스트 이름이 풀리지 않을 수 있습니다).
  2. 입력의 Device EUIs 필터를 확인합니다. 업링크의 DevEUI와 다르면 설계상 조용히 버려집니다.
  3. 구독 토픽이 ChirpStack v4 업링크 토픽과 여전히 맞는지 확인합니다.
  4. 입력의 로그 수준을 디버그로 올리고 로그를 봅니다. 업링크마다 평가한 표현식과 결과가 남습니다. 결과가 null인 것 — 경로가 틀렸거나 코덱이 디코딩하지 않는 것 — 이 "연결은 되는데 저장이 없는" 입력의 가장 흔한 원인입니다.
  5. 활성화할 측정값 선택에서 그 채널이 켜져 있는지 확인합니다. 꺼진 채널은 저장 직전에 버려집니다.
  6. ChirpStack의 코덱이 실제로 페이로드를 디코딩하는지 확인합니다. 이벤트 JSON의 object가 비어 있으면 object. 아래 어떤 표현식도 값을 낼 수 없습니다.

명령이 장치에 닿지 않습니다.

  1. 장치의 클래스를 확인합니다. Class A라면 큐에 든 다운링크가 다음 업링크를 기다리고, 하트비트가 길면 수 분이 걸릴 수 있습니다.
  2. ChirpStack에서 그 장치의 큐를 봅니다. 프레임이 큐에 쌓여 있다면 AoT 쪽은 정상이고 전달이 문제입니다. 큐가 비었는데 AoT에서 실패했다면 전송 자체가 실패한 것이므로 그 출력의 gRPC 서버와 키를 확인하십시오 — 등록 시점에 복사된 값이라 낡았을 수 있습니다.
  3. 하나씩 보내면 되는데 여러 개를 몰아 보낼 때만 실패한다면 페이싱입니다. ChirpStack의 RX2 데이터레이트가 AoT의 페이싱 기준과 맞는지 확인하고, 같은 순간에 조작하는 장치 수를 줄이십시오.
  4. 출력은 실패라고 하는데 장치는 실제로 동작했다면 확인 응답이 돌아오지 못하는 것입니다. MQTT 브로커 설정과, 펌웨어의 확인 응답 포트·형식이 이 모듈이 기대하는 것과 같은지 확인하십시오.
  5. 한 채널에서 실패가 반복되면 그 채널은 두절로 표시되고 이후 명령은 단발 탐침으로만 나갑니다. 의도된 동작이며, 확인이 한 번 오면 풀립니다.

평소에는 되는데 부하가 걸리면 나빠집니다. 거의 언제나 페이싱과 RX2의 상호작용입니다. 명령 시한을 손대기 전에 다운링크 페이싱을 먼저 읽으십시오 — 재전송을 더 얻으려고 시한을 늘리면 이미 포화된 링크는 더 나빠집니다.

일반적인 장치·데몬 문제는 문제 해결을 보십시오.