MQTT
외부 MQTT 브로커를 통해 일반 MQTT 또는 Sparkplug B로 발행하는 장치를 다루며, 브로커를 그 아래의 모든 장치가 함께 쓰는 노드로 둡니다. 스테이션 자체의 데이터를 브로커에 발행하기도 합니다.
MQTT 드라이버는 외부 MQTT 브로커를 통해 발행하는 장비의 태그를 읽고 씁니다. 게이트웨이, 무선 센서, Node-RED 흐름, Sparkplug B를 쓰는 엣지 노드 같은 것입니다. 스테이션은 그 브로커의 클라이언트로, 태그가 읽는 토픽을 구독하고 사용자가 한 쓰기를 발행합니다. 또한 어느 브로커든 자기 발행 카드에 넣은 태그, Logic 변수, 경보 같은 스테이션 자체의 데이터를 JSON 또는 Sparkplug B로 발행할 수 있습니다. 스테이션은 클라이언트이지 브로커가 아니므로 장비와 스테이션은 둘 다 브로커에 접속합니다. 브로커가 없으면 스테이션 자체의 MQTT 브로커가 그 브로커가 될 수 있으며, 켜면 이 드라이버에 브로커 이 스테이션이 추가됩니다. 따로 브로커를 마련하는 방법은 브로커 설치에 있습니다.
브로커 뒤의 장치는 모두 같은 연결을 쓰므로 구조는 드라이버 > 브로커 > 장치 > 태그입니다. 브로커가 응답하는 위치와 스테이션의 로그인 방법을 한 번만 가지고, 그 아래의 각 장치는 발행 방식(일반 MQTT 또는 Sparkplug B)과 자기 태그만 가집니다. 두 프로토콜은 한 브로커 아래에 나란히 함께 있습니다. 값은 주기적 읽기가 아니라 구독으로 오므로 MQTT 장치에도 태그에도 읽기 주기가 없습니다.
드라이버 페이지
MQTT 드라이버 페이지는 장치 대신 브로커를 나열합니다. 머리글 아래 문장은 "각 브로커는 외부 MQTT 브로커로의 연결 하나입니다. 응답하는 위치와 스테이션의 로그인 방법을 설정한 다음, 그 브로커를 통해 발행하는 장치를 추가하십시오."입니다. MQTT 브로커 표는 제목 오른쪽에 브로커 추가를 두고 브로커마다 한 행을 둡니다. 이름, 주소(mqtt://host:port, TLS에서는 mqtts://host:port이며 브로커에 호스트가 없는 동안은 비어 있음), 장치, 상태(점과, 브로커 상태에 장치들의 모습을 붙인 문구. 예: "온라인 · 장치 2/2개 온라인"), 그다음 열기와, Connector 구성 권한이 있으면 사용, 사용 안 함, 삭제입니다. 빈 표는 "아직 브로커가 없습니다."라고 합니다. 스테이션을 거부한 브로커는 이름 뒤에 트리와 같은 빨간 표시가 붙고, 페이지 머리글 아래에는 오류가 있는 브로커의 이름이 나옵니다("오류가 있는 브로커 1개: Plant").
트리에서 드라이버 행은 두 단계를 셉니다("브로커 1개 · 장치 2개"). 페이지 머리글은 브로커 수를 괄호 안에 보여 줍니다. 열의 새로 만들기… 메뉴에서는 MQTT 항목에 새 브로커가 있고, 그 뒤에 각 브로커가 자기 새 장치와 장치를 거느리고 나옵니다. 드라이버 행을 오른쪽 단추로 누르면 브로커 추가가 나옵니다. 드라이버의 명령 모음에는 장치 검색이 없습니다. 스캔은 브로커 하나에서 수신하므로 브로커 페이지에 있습니다. 추가한 드라이버는 브로커가 있든 없든 트리의 드라이버 폴더 아래에 놓입니다.
브로커
브로커 추가, 새로 만들기… 메뉴의 새 브로커, 드라이버 행의 오른쪽 단추 메뉴는 "새 브로커"(다음은 "새 브로커 2")라는 브로커를 사용 안 함 상태로 만듭니다. 스테이션이 접속하기 전에 연결을 채울 수 있게 하기 위해서입니다. 작업 기록 줄도 그렇게 알립니다. "사용 안 함 상태로 브로커 '새 브로커'을(를) 추가했습니다. 응답하는 위치를 입력한 다음 사용으로 바꾸십시오." 브로커는 열리지 않습니다. 드라이버 페이지의 MQTT 브로커 표에서 강조 표시되며, 새로 만들기…나 오른쪽 단추 메뉴에서는 화면이 그 페이지로 갑니다. 행의 열기나 트리의 그 행으로 여는 브로커 페이지는 "MQTT 브로커 하나입니다. 응답하는 위치와 스테이션이 로그인하는 방법을 정합니다. 그 아래의 모든 장치가 이 연결을 함께 씁니다."라는 문장과, 머리글에 상태와 점과 주소를 보여 줍니다. 머리글 아래에는 브로커의 장치 가운데 자기 오류가 있는 장치의 이름이 나옵니다("오류가 있는 장치 1개: Pump"). 브로커 자체에 오류가 있는 동안에는 장치들이 브로커를 가리킵니다. 장치 페이지는 "이 장치는 브로커 Plant을(를) 거치는데, 그 브로커에 오류가 있습니다. 이유는 브로커 페이지에 있습니다."라고 말합니다.
브로커 연결 카드
| 칸 | 뜻 | 기본값 |
|---|---|---|
| 이름 | 트리와 그 아래 각 장치에 보이는 브로커의 이름입니다. 주소에는 절대 들어가지 않습니다. 비우면 거부됩니다. "브로커 이름은 반드시 입력해야 합니다." | "새 브로커" |
| 호스트 | 브로커의 호스트 이름이나 IP 주소입니다. 주소 전체를 붙여 넣을 수 있습니다. 앞에 mqtt://나 tcp://가 있으면 전송 방식이 평문이 되고, mqtts://, ssl://, tls://이면 TLS가 되며, 호스트 뒤의 포트는 포트로 가고 호스트는 그것만 저장됩니다. 다른 스킴, 경로, 로그인 정보가 주소에 들어 있으면 칸 아래에서 거부되고 각 칸은 원래 값을 지킵니다. "'http://192.168.0.20'은(는) 브로커 주소가 아닙니다. 브로커의 호스트 이름이나 IP 주소를 쓰십시오. mqtt://host:port 또는 mqtts://host:port 형식도 됩니다." |
비어 있음 |
| 포트 | 브로커가 응답하는 TCP 포트이며 1에서 65535까지입니다. | 1883 |
| 전송 방식 | 확인란 TLS 사용입니다. 켜면 연결이 암호화되고 브로커의 인증서를 Windows 인증서 저장소 또는 현장 장비 접근에서 승인한 인증서로 확인합니다. "암호화됨: Windows가 브로커의 인증서를 신뢰하거나, MQTT 드라이버 페이지의 현장 장비 접근에서 그 인증서를 승인해야 합니다." 끄면 안내가 "암호화 안 됨: 값과 비밀번호가 평문으로 전송됩니다."라고 경고합니다. 바꾸면 1883에 둔 포트는 8883으로, 그 반대로도 옮겨지고, 다른 포트는 그대로 둡니다. | 꺼짐 |
| 사용자 이름, 비밀번호 | 스테이션이 브로커에 로그인하는 계정입니다. 사용자 이름이 비어 있으면 익명으로 로그인합니다. 비밀번호는 장치의 자격 증명처럼 저장 시 보호되며 주소, 진단 로그, 에이전트의 응답에는 절대 나타나지 않습니다. | 비어 있음 |
| 클라이언트 ID | 스테이션의 세션이 브로커에서 갖는 이름으로, 제어 문자 없이 1자에서 128자까지입니다. 브로커는 클라이언트 ID마다 세션 하나를 두고 둘이면 오래된 쪽을 끊으므로, 클라이언트 ID는 이 스테이션의 브로커 하나에만 속합니다. "클라이언트 ID 'GanterLab01'은(는) 이미 브로커 'Plant'의 것입니다. 클라이언트 ID가 같은 두 세션은 서로를 브로커에서 밀어냅니다. 다른 ID를 고르십시오." 두 스테이션이 한 브로커를 함께 쓰면 각자 자기 ID를 둡니다. | GanterLab과 16진수 14자리, 자동 생성 |
| 킵얼라이브(s) | 다른 것이 오가지 않을 때 세션이 살아 있음을 알리는 간격입니다. "킵얼라이브는 5에서 3600초 사이여야 합니다." | 60 |
칸들 아래 문장은 브로커와 그 장치들이 무엇을 하고 있는지, 브로커에 아직 무엇이 모자란지 알리고 "이 브로커 아래의 모든 장치와 스테이션이 이 브로커에 발행하는 것이 이 연결을 함께 씁니다. 사용으로 된 첫 장치나 발행할 행이 필요할 때 세션이 열립니다."로 이어집니다. 브로커가 사용 중인 동안에도 모든 칸을 편집할 수 있습니다. 응답하는 위치, 전송 방식, 로그인, 클라이언트 ID, 킵얼라이브의 변경을 저장하면 브로커 아래 모든 장치가 함께 쓰는 세션 하나가 다시 연결됩니다.
명령 모음
| 명령 | 하는 일 | 회색이 되는 때(상황) | 그려지지 않는 때(역할) |
|---|---|---|---|
| 사용 | 브로커 아래 장치들이 그 세션을 쓰게 합니다. 호스트가 없는 브로커는 거부됩니다. "브로커를 사용으로 바꾸기 전에 브로커의 호스트 이름이나 IP 주소를 입력하십시오." | 이미 사용 중일 때, 연결이 완전하지 않을 때("이 브로커의 연결 설정이 아직 완전하지 않습니다."), 스캔이 진행 중일 때, 또는 스테이션이 변경을 거부할 때. | Connector 구성 권한이 없을 때. |
| 사용 안 함 | 그 아래 모든 장치에 대해 세션을 닫습니다. 각 장치는 자기 사용 선택을 지키며, 브로커를 다시 사용으로 바꾸면 그대로 돌아옵니다. | 이미 사용 안 함일 때, 스캔이 진행 중일 때, 또는 스테이션이 변경을 거부할 때. | Connector 구성 권한이 없을 때. |
| 브로커 삭제(위험을 나타내는 색, 오른쪽) | 먼저 묻습니다. 빈 브로커면 "이 브로커에는 장치가 없습니다.", 장치가 있으면 "이 브로커의 장치 2개와 그 장치들의 태그도 함께 삭제됩니다." 그다음 MQTT 드라이버가 선택되고 작업 기록 줄에 "브로커 'Plant'과(와) 그 장치 2개를 삭제했습니다."가 나옵니다. | 스캔이 진행 중일 때("장치 검색 스캔이 이 브로커를 쓰고 있습니다. 끝날 때까지 기다리십시오."), 또는 스테이션이 변경을 거부할 때. | Connector 구성 권한이 없을 때. |
브로커 행을 오른쪽 단추로 누르면 장치 추가, 사용, 사용 안 함, 삭제가 나옵니다.
브로커 상태
브로커는 자기 세션을 장치와 따로, 트리 행, 드라이버의 브로커 표, 자기 머리글에서 알립니다.
| 상태 | 점 | 뜻 |
|---|---|---|
| 꺼짐 | 회색 | 브로커가 사용 안 함입니다. |
| 세션 없음 | 회색 | 사용 중이지만 그 브로커를 쓰는 사용 중인 장치가 없고 발행 카드도 아무것도 발행하지 않아 세션을 열지 않았습니다. |
| 연결하는 중… | 호박색 | 장치가 사용 중이거나 브로커가 발행 중이고, 세션이 연결하는 중이거나, 끊긴 뒤 다시 연결하는 중입니다. |
| 온라인 | 녹색 | 세션이 연결되어 있습니다. |
| 연결할 수 없음 | 빨간색 | 브로커에 닿지 못했거나 브로커가 스테이션을 거부했습니다. 원인은 머리글 아래 스테이션의 언어로 된 빨간 글씨와, 드라이버의 말 그대로 행의 오류 표시 도구 설명으로, 고칠 점의 말로 적힙니다. 그 포트에서 아무것도 응답하지 않음, 이 네트워크에서 알 수 없는 이름, 거부된 사용자 이름이나 비밀번호, 신뢰되지 않거나 현장 장비 접근에서 승인을 기다리는 인증서, 같은 클라이언트 ID로 다른 클라이언트가 세션을 가져감 같은 것입니다. 포트를 거부하거나 사용자 이름 없는 클라이언트를 거부하는 브로커는 대신 그 설정으로 알려 줍니다(브로커 준비 참고). |
트리 행은 상태와 장치 수를 보여 주고("온라인 · 장치 2개"), 카드 아래 요약은 장치들의 모습을 더합니다. "온라인 · 장치 2/2개 온라인", "온라인 · 1개 온라인 · 1개 문제 있음", "세션 없음 · 사용 중인 장치 없음"입니다. 죽음을 알린 Sparkplug B 장치는 자기만 통신에서 빠지고 브로커는 온라인으로 남습니다. 세션은 MQTT 5로 말하고, 그것을 쓰지 않는 브로커에는 MQTT 3.1.1로 내려갑니다. 깨끗한 상태로 시작하고 스스로 다시 연결하며, 브로커가 돌아오지 않는 동안에는 시도 사이의 간격을 점점 늘립니다.
장치 검색 카드
Connector 구성 권한이 있을 때만 그려지며, "이 브로커에서 잠시 수신합니다. 스스로를 알리는 Sparkplug B 엣지 노드와 장치, 그리고 필터 아래의 토픽을 모읍니다."라는 문장 아래에 있습니다.
| 칸 | 뜻 | 기본값 |
|---|---|---|
| 수신 시간(s) | 스캔이 수신하는 시간으로 3에서 60초까지입니다. | 10 |
| 토픽 필터 | 장치 하나의 태그로 나열할 일반 토픽입니다. 와일드카드 +(한 단계)와 #(그 단계와 그 아래 전부, 마지막에만)를 쓸 수 있으므로 "예: plant/#"처럼 씁니다. 비어 있으면 Sparkplug B 장치만 나열합니다. |
비어 있음 |
장치 검색은 스캔을 시작하고, 진행되는 동안 취소로 바뀝니다. 칸 아래 문장은 스캔이 할 일을 알리고("192.168.0.20:1883을(를) 10 s 동안 수신합니다."), 진행 문장은 시간 창을 셉니다("192.168.0.20:1883 수신하는 중 · 10 s 중 4 s…"). 스캔에는 브로커에 저장된 호스트가 필요하며, 그 전까지 카드는 "장치 검색 전에 브로커의 호스트를 입력하고 편집이 저장되게 하십시오."라고 합니다. 브로커에 남은 편집은 먼저 저장되며, 저장할 수 없으면 아무것도 시작하지 않습니다. "브로커 편집을 저장하지 못해 장치 검색을 시작하지 않았습니다."
스캔이 브로커에서 하는 일:
- 자기만의 클라이언트 ID로 접속하므로 장치들의 세션을 브로커에서 밀어내지 않으며, 브로커가 사용 중이고 쓰이고 있어도 실행할 수 있습니다.
- 모든 Sparkplug B 토픽(
spBv1.0/#)과 토픽 필터를 구독합니다. Sparkplug B 탄생 인증서는 보존되지 않으므로, 그것 없이 들린 엣지 노드에는 다시 알려 달라고 요청합니다(Node Control/Rebirth명령이며 스캔이 발행하는 유일한 메시지입니다). 실행 중인 엣지 노드는 시간 창 안에 응답합니다. - 스스로를 알린 각 엣지 노드와 그 뒤의 각 장치(NBIRTH, DBIRTH)는 메트릭을 태그로 가진 후보가 되며, 형식은 탄생이 선언한 대로입니다. 엣지 노드 자신의 장치(
bdSeq와Node Control/…,Device Control/…메트릭)는 빠지고, 어떤 태그도 읽지 않는 메트릭(배열, 데이터 세트, 템플릿, 속성 세트, 바이트, 파일)도 이유별로 세어서 빠집니다. 들렸지만 시간 창 안에 탄생하지 않은 엣지 노드는 태그 없이 제시됩니다. - 토픽 필터가 있으면, 그 아래에서 들린 일반 토픽은 따로 후보 하나가 됩니다. 각 토픽이 태그 하나가 되며, JSON 페이로드라면 그 안의 각 값이 값 경로로 태그 하나가 됩니다(토픽마다 최대 32개, 깊이 4단계까지, 배열은 앞의 8개 요소). 숫자는 Double,
true나false는 Boolean, 그 밖은 String으로 제시됩니다. 목록은 500개 토픽에서 멈춥니다. 발행자가 마지막 메시지를 보존하는 토픽은 바로 들리고, 다른 토픽은 시간 창 안에 발행할 때만 들립니다. - 후보를 추가하기 전에는 아무것도 저장되지 않습니다. 취소하면 시간 창이 바로 끝납니다.
결과 카드 검색된 장치는 발행 형태(group/edge node, 엣지 노드 뒤의 장치면 /device가 붙음, 또는 "일반 토픽"), 장치(추가할 때의 이름으로 편집할 수 있음. 장치 ID나 엣지 노드 ID, 또는 필터의 첫 와일드카드 앞 단계들), 결과("태그 12개 중 12개 선택됨"), 그리고 장치 추가를 나열합니다. 장치 추가는 이 브로커 아래에 그 태그들로 장치를 만듭니다. 브로커에 이미 설정된 Sparkplug B 식별은 "이미 설정됨"으로 보이고 대신 열기를 내놓습니다. 아무것도 듣지 못한 스캔은 "스캔이 수신하는 동안 이 브로커에서 자신을 알린 것이 없습니다."라고 합니다.
이미 있는 장치는 아직 읽지 않는 것을 자기 페이지에서 찾습니다. 태그 카드 머리의 태그 검색은 브로커에서 10초 동안 듣습니다. Sparkplug B 장치는 자기 엣지 노드만 듣고 그 노드에 탄생을 요청하며 다른 엣지 노드에는 아무것도 요청하지 않습니다. 일반 장치는 태그가 공유하는 단계 아래의 토픽(plant/oven/temperature와 plant/oven/count라면 plant/oven/#)을 듣고, 공유하는 단계가 없으면 브로커의 모든 토픽을 듣습니다. 아직 태그가 없는 값만 제시됩니다(장치의 태그 검색 참고).
장치 카드
"각 장치는 일반 토픽 또는 Sparkplug B 엣지 노드나 장치 하나를 읽습니다. 연결은 브로커에서 물려받으며 여기에서 바꿀 수 없습니다." 장치 추가는 이 브로커 아래에 "새 장치"를 사용 중, 일반 MQTT로 만들고, 이 표에서 강조 표시해 보이는 곳까지 스크롤합니다. "'Plant'에 장치 '새 장치'을(를) 추가했습니다." 표는 장치, 발행 형태, 태그, 상태 건전성을 나열하고 각 행에 열기, 사용, 사용 안 함, 삭제가 있습니다. 비어 있으면 "이 브로커에 설정된 장치가 없습니다."라고 합니다. 자기 오류가 있는 장치는 이름 뒤에 트리와 같은 빨간 표시가 붙습니다.
발행 카드
마지막 카드는 스테이션 자체의 데이터를 이 브로커에 발행하며, 카드에는 "값이나 그 품질이 바뀔 때마다 스테이션은 각 행을 JSON으로 이 브로커의 해당 토픽에 발행하고, 연결이 열릴 때마다 모든 행을 다시 발행합니다. 브로커는 나중에 구독하는 쪽을 위해 각 토픽의 마지막 메시지를 보관합니다. 스테이션은 읽기와 쓰기로 둔 각 행의 쓰기 토픽만 구독합니다."라고 적혀 있습니다. Connector를 볼 수 있는 사람은 카드를 읽고, 구성할 수 있는 사람은 바꿉니다. 스테이션 자체의 MQTT 브로커를 위한 브로커 이 스테이션에도 같은 카드가 있습니다.
| 칸 | 뜻 | 기본값 |
|---|---|---|
| 발행 형식 | 행을 내보내는 방식입니다. 각 행의 토픽에 JSON으로 내보내거나(발행), 스테이션을 브로커의 엣지 노드로 삼아 Sparkplug B로 내보냅니다(Sparkplug B로 발행). 도구 설명은 "행을 내보내는 방식입니다. 각 행의 토픽에 JSON으로 내보내거나, Sparkplug B로 내보냅니다. Sparkplug B에서는 이 스테이션이 엣지 노드가 되어 Ignition 같은 Sparkplug B 소비자가 스스로 찾습니다."입니다. | JSON |
| 토픽 접두사 | JSON일 때만입니다. 새 행의 토픽을 제안할 때 그 아래에 두는 단계입니다. 비워 두면 칸에 기본값이 보이고 그것이 쓰입니다. "토픽 접두사에는 +나 #를 넣을 수 없고, $로 시작하거나 토픽에 쓸 수 없는 문자를 넣을 수도 없습니다." 바꿔도 목록에 이미 있는 토픽은 그대로입니다. | ganterlab/와 스테이션 이름 |
| 그룹 ID | Sparkplug B일 때만 접두사 자리에 나옵니다. 이 브로커에서 스테이션 엣지 노드의 Sparkplug B 그룹이며, 비워 두면 GanterLab입니다. /, +, #를 담은 그룹은 칸 아래에서 거부되고, 고칠 때까지 브로커는 저장되지 않습니다. |
GanterLab |
Sparkplug B일 때 제목 아래 문장은 대신 "이 브로커에서 스테이션은 Sparkplug B 엣지 노드입니다. Logic의 변수와 경보는 엣지 노드 자신의 메트릭이 되고, 행이 있는 장치는 각각 Sparkplug B 장치가 됩니다. 연결이 열릴 때와 목록이 바뀔 때마다 모든 메트릭을 알리고, 그 뒤에는 바뀐 값과 품질을 발행합니다. 명령에서 값을 받는 것은 읽기와 쓰기로 둔 행뿐입니다."가 되고, 칸 아래 엣지 노드 ID(스테이션 이름)에 발행에 쓰는 엣지 노드가 나옵니다.
표에는 신호원, 토픽, 접근이 토픽 순서로 나옵니다. 신호원을 아직 고르지 않은 행은 "아직 신호원 없음"입니다. 행이 없으면 "아직 이 브로커에 발행하는 것이 없습니다. 새 행으로 추가하십시오."가 나옵니다. 브로커가 사용 안 함이고 목록에 행이 있으면 "브로커가 사용 안 함 상태이므로 사용으로 바꿀 때까지 아무것도 발행하지 않습니다."라는 알림이 나옵니다. 브로커의 행 중 하나라도 읽기와 쓰기이면 "읽기와 쓰기로 둔 행은 쓰기 토픽에 발행된 값을 받습니다. 이 브로커에 발행할 수 있는 누구나 그 신호원을 바꿀 수 있으므로, 브로커의 사용자 이름과 비밀번호가 유일한 보호 수단입니다."라는 두 번째 알림이 나옵니다. Sparkplug B일 때는 "읽기와 쓰기로 둔 행은 Sparkplug B 명령(NCMD, DCMD)에서 값을 받습니다. 이 브로커에 발행할 수 있는 누구나 그 신호원을 바꿀 수 있으므로, 브로커의 사용자 이름과 비밀번호가 유일한 보호 수단입니다."가 나옵니다. Sparkplug B일 때 토픽 열은 메트릭이 됩니다. 태그는 장치 뒤에(Oven · Temperature), 변수와 경보는 엣지 노드의 이름으로(Logic/Oven/Setpoint, Alarms/High) 나옵니다.
| 명령 | 하는 일 | 회색이 되는 때(상황) | 그려지지 않는 때(역할) |
|---|---|---|---|
| 새 행 | 아직 아무것도 발행하지 않는 행을 추가하고 선택합니다. "브로커의 발행 목록에 행을 추가했습니다. 신호원을 고르십시오."가 나옵니다. | 실행 기록이 스테이션을 잡고 있을 때, 또는 런타임이 멈춰 있을 때. | Connector 구성이 없을 때. |
| 행 삭제(위험 색) | 선택한 행을 바로 삭제하며, 도구 설명에 그 행이 발행하는 것이 나옵니다. 스테이션은 그 발행을 멈추지만, 브로커가 그 토픽에 보관한 메시지는 남습니다. | 선택한 행이 없을 때("삭제할 행을 목록에서 고르십시오."), 실행 기록이 스테이션을 잡고 있을 때, 또는 런타임이 멈춰 있을 때. | Connector 구성이 없을 때. |
행의 칸은 바뀌는 순간 저장됩니다.
| 필드 | 하는 일 |
|---|---|
| 신호원 | 행이 발행하는 것입니다. "(없음)"에 이어 사용 중인 장치의 사용 중인 태그("태그 · Simulated · Oven · Temperature"), 값을 담는 Logic 변수, 경보가 폴더가 붙은 이름으로 나옵니다. 장치 명령은 아무것도 발행하지 않으므로 나오지 않습니다. 행은 신호원을 식별로 붙잡으므로 이름을 바꿔도 그 신호원에 남으며, 신호원의 사용처 카드에 이 행이 나옵니다. |
| 토픽 | JSON일 때만입니다. 행이 발행하는 곳입니다. 신호원을 고르면 그 이름으로 토픽이 제안됩니다. 태그는 <prefix>/<device>/<tag>, 변수는 <prefix>/logic/<folders>/<variable>, 경보는 <prefix>/alarms/<folders>/<alarm>이며, 이름은 각각 토픽의 한 단계가 됩니다(공백, 슬래시, 와일드카드는 _가 됩니다). 마음대로 고칠 수 있습니다. 아직 제안된 그대로인 토픽은 나중에 고른 신호원을 따라 바뀌고, 직접 쓴 토픽은 그대로 남으며, 신호원 이름을 바꿔도 바뀌지 않습니다. |
| 접근 | 읽기 전용은 모든 행의 기본값이며, 스테이션은 행을 발행하고 그것을 위해 아무것도 구독하지 않습니다. 읽기와 쓰기로 두면 스테이션은 행의 쓰기 토픽(행의 토픽 뒤에 /set을 붙인 것)에 발행된 값도 받아 신호원에 씁니다(되쓰기). 쓰는 드라이버의 쓰기 접근이 있는 태그나 내부 값 변수에만 제공됩니다. 다른 신호원에서는 목록에 회색으로 남고 "이 신호원은 쓰기를 받지 않습니다. 쓰기를 받는 것은 쓰기 접근이 있는 태그나 내부 값 변수뿐입니다."가 나옵니다. 경보를 고르면 행은 읽기 전용으로 돌아갑니다. Sparkplug B일 때 읽기와 쓰기는 쓰기 토픽 대신 Sparkplug B 명령이 행의 메트릭에 보낸 값을 받습니다. |
칸 아래 문장은 행이 무엇을 발행하는지 알립니다.
| 카드가 말하는 것 | 나오는 때 |
|---|---|
| "이 행은 아직 아무것도 발행하지 않습니다. 신호원을 고르십시오." | 신호원을 고르지 않았을 때. |
| "값이나 품질이 바뀔 때마다 값, 그 품질, 시각을 JSON으로 발행합니다." | 읽기 전용인 태그나 변수일 때. |
| "값이나 품질이 바뀔 때마다 값, 그 품질, 시각을 JSON으로 발행하고, 쓰기 토픽에 발행된 각 값을 신호원에 씁니다. 쓰기는 브로커 이름과 함께 진단 로그에 기록됩니다." | 읽기와 쓰기인 태그나 변수일 때. |
| "경보의 발생 여부와 확인 여부, 상태, 우선순위, 메시지, 시각 중 하나라도 바뀌면 이를 JSON으로 발행합니다." | 경보일 때. |
| "이 행의 신호원은 더 이상 없으므로 이 행으로는 더 이상 발행하지 않습니다. 브로커는 마지막으로 보관한 메시지를 그대로 둡니다." | 태그, 변수, 경보가 삭제되었을 때. |
| "값이나 품질이 바뀔 때마다 값과 그 품질을 Sparkplug B로 발행합니다." | Sparkplug B에서 읽기 전용인 태그나 변수일 때. |
| "값이나 품질이 바뀔 때마다 값과 그 품질을 Sparkplug B로 발행하고, Sparkplug B 명령이 그 메트릭에 보낸 각 값을 신호원에 씁니다. 쓰기는 브로커 이름과 함께 진단 로그에 기록됩니다." | Sparkplug B에서 읽기와 쓰기인 태그나 변수일 때. |
| "경보의 발생 여부와 확인 여부, 상태, 우선순위, 메시지 중 하나라도 바뀌면 이를 Sparkplug B로 발행합니다." | Sparkplug B에서 경보일 때. |
| "이 행의 신호원은 더 이상 없으므로 엣지 노드는 그것을 빼고 다시 자신을 알립니다." | Sparkplug B에서 태그, 변수, 경보가 삭제되었을 때. |
그 문장 아래에 읽기와 쓰기인 행은 쓰기 토픽(행의 토픽 뒤에 /set을 붙인 것)을 보여 줍니다. Sparkplug B에는 쓰기 토픽이 없습니다. 대신 두 번째 문장이 행이 어떤 메트릭으로 발행되는지 알려 줍니다. 태그는 Sparkplug B 장치의 메트릭, 변수는 스테이션 엣지 노드의 메트릭, 경보는 그 이름 아래의 다섯 메트릭(Active, Acked, State, Priority, Message)입니다.
목록이 거부하는 변경은 저장되지 않습니다. 이유는 행의 칸 위에 빨간 글씨로 나오고, 고칠 수 있도록 변경은 화면에 남습니다.
| 카드가 말하는 것 | 나오는 때 |
|---|---|
| "이 신호원은 이미 이 브로커에 발행되고 있습니다. 발행하는 행을 편집하십시오." | 이 브로커의 다른 행이 그 신호원을 발행할 때. |
| "이 브로커의 다른 행이 이미 이 토픽에 발행하고 있습니다. 이 행에는 다른 토픽을 지정하십시오." | 한 브로커의 두 행이 같은 토픽에 발행하게 될 때. |
| "필터에는 아무것도 발행할 수 없으므로 토픽에 + 또는 #를 넣을 수 없습니다." | 토픽에 와일드카드가 있을 때. |
| "\(로 시작하는 토픽은 브로커의 것입니다. 다른 토픽을 쓰십시오." | 토픽이 `\)`로 시작할 때. | |
| "이 토픽은 보낼 수 없습니다. 토픽에 쓸 수 없는 문자가 있거나 너무 깁니다." | 제어 문자가 있거나 MQTT 토픽이 담을 수 있는 길이를 넘을 때. |
| "쓰기를 받는 행에는 쓰기가 갈 태그나 변수가 있어야 합니다." | 신호원보다 먼저 읽기와 쓰기를 골랐을 때. |
| "이 신호원에는 쓸 수 없습니다. 쓰기 접근이 있는 태그나 내부 값 변수를 고르거나, 행을 읽기 전용으로 두십시오." | 경보, 수식 변수, 읽기 전용 태그, 아무것도 쓰지 않는 드라이버의 태그에서 읽기와 쓰기를 골랐을 때. |
| "이 토픽과 이 브로커의 다른 행 토픽은 행이 쓰기를 받는 /set만 다릅니다. 이 행에는 다른 토픽을 지정하십시오." | 한 행의 토픽이 다른 행의 토픽 뒤에 /set을 붙인 것일 때. |
| "목록의 이 행은 더 이상 없습니다. 다시 불러온 뒤 다시 시도하십시오." | 편집하는 동안 그 행이 다른 곳에서 삭제되었을 때. |
무엇을 언제 발행하는지는 발행에 있습니다.
장치
| 칸 | 뜻 | 기본값 |
|---|---|---|
| 브로커 · 고정 | 브로커 이름과 그 아래 주소이며 읽기 전용입니다. 장치는 자기 브로커 아래에서 만들어지고 거기에 머뭅니다. 주소 자리에는 "브로커에 아직 호스트가 없습니다"가 올 수 있습니다. "브로커 없음"은 장치가 브로커를 잃어 저장할 수 없다는 뜻입니다. "MQTT 브로커를 지정해야 합니다." | 추가한 브로커 |
| 프로토콜 | 장치가 발행하는 방식입니다. 일반 MQTT: "각 태그는 읽을 토픽을, JSON 페이로드라면 값까지의 경로도 함께 지정합니다." Sparkplug B: 엣지 노드 하나, 또는 그 뒤의 장치 하나입니다. "각 태그는 엣지 노드의 탄생 인증서(birth)가 선언한 대로 메트릭 이름을 씁니다. 형식은 메트릭과 함께 옵니다." 바꾸면 주소가 토픽이나 메트릭으로 읽히게 되므로 각 태그를 다시 확인합니다. | 일반 MQTT |
| 메시지 없이 지날 수 있는 최대 시간 (s) | 일반 MQTT만이며, 0에서 86400까지이고 0은 기한 없음입니다. "이 시간 동안 토픽에 메시지가 오지 않으면 그 태그를 읽은 값으로 치지 않습니다. 0은 기한 없음으로, 값이 바뀔 때만 발행되는 토픽에 씁니다. 몇 초마다 보고하는 센서처럼 일정한 간격으로 발행하는 장치에는 값을 넣으십시오." 이 범위를 벗어나면 장치가 저장되지 않습니다. "메시지 없이 지날 수 있는 최대 시간은 0에서 86400초 사이여야 합니다." Sparkplug B 장치에는 없습니다. 죽음 인증서가 이미 사라졌음을 알리기 때문입니다. | 0 |
| 그룹 ID | Sparkplug B만. 엣지 노드가 발행하는 그룹이며, 토픽에서 spBv1.0 다음 단계입니다. "Sparkplug B 장치에는 그룹 ID가 있어야 합니다." |
비어 있음 |
| 엣지 노드 ID | Sparkplug B만. 메트릭을 발행하는 엣지 노드이며, NBIRTH가 부르는 이름 그대로입니다. "Sparkplug B 장치에는 엣지 노드 ID가 있어야 합니다." | 비어 있음 |
| 장치 ID | Sparkplug B만. 엣지 노드 뒤의 장치이며, DBIRTH가 부르는 이름 그대로입니다. 비어 있으면("엣지 노드 자체"로 표시) 엣지 노드 자신의 메트릭을 읽습니다. | 비어 있음 |
장치는 자기 호스트, 포트, 자격 증명, 읽기 주기를 갖지 않습니다. 모두 브로커의 것입니다. Sparkplug B의 각 ID는 토픽의 한 단계입니다. "Sparkplug B ID에는 '/', '+', '#'를 넣을 수 없습니다." 브로커는 Sparkplug B 엣지 노드나 장치를 한 번만 부르므로, 같은 브로커에서 그룹, 엣지 노드, 장치 ID가 같은 두 번째 장치는 거부됩니다. "브로커 'Plant'의 Sparkplug B 장치 Plant/Line1/Press1은(는) 이미 장치 'Press'의 것입니다." 일반 MQTT 장치는 브로커에서 자기 것을 아무것도 부르지 않으므로 두 장치가 같은 토픽을 읽어도 됩니다.
머리글이 보여 주는 기본 URI는 실행 시 주소입니다. mqtt://<broker id>?host=…&port=…&tls=0&keepAlive=60&clientId=…&mode=plain이며(장치가 메시지 없이 지날 수 있는 최대 시간을 정하면 &silence=…가 붙습니다), Sparkplug B 장치에서는 mode=sparkplug&group=…&node=…이고 엣지 노드 뒤의 장치에는 &device=…가 붙습니다. 브로커를 표시 이름이 아니라 변하지 않는 식별로 부르며, 사용자 이름이나 비밀번호는 절대 담지 않습니다.
MQTT 장치의 복사본은 같은 브로커에 남습니다. Sparkplug B 복사본은 그 브로커의 어떤 장치도 갖지 않은 첫 식별을 가집니다. 가장 안쪽 ID(장치 ID, 엣지 노드 자신의 메트릭이면 엣지 노드 ID)에 복사본 이름과 같은 방식으로 번호가 붙습니다("Press1 (2)").
태그 주소 지정
주소 칸은 일반 MQTT 장치에서는 토픽, Sparkplug B 장치에서는 메트릭이며 반드시 필요합니다("이 드라이버에는 토픽이(가) 반드시 필요합니다."). 일반 태그에는 칸이 세 개 더 있고, Sparkplug B 메트릭에는 없습니다. 메트릭은 자기 형식을 가지고 프로토콜 자체의 명령으로 쓰이기 때문입니다.
| 칸 | 뜻 | 기본값 |
|---|---|---|
| 토픽 | 태그가 읽는 토픽 하나입니다. 예: plant/line1/temperature. "태그는 토픽 하나를 읽으므로 토픽에 와일드카드 + 또는 #를 넣을 수 없습니다." |
필수 |
| 값 경로 | JSON 페이로드 안에서 값이 있는 자리입니다. 점으로 구분한 멤버와 대괄호 안의 배열 인덱스로 씁니다. 예: sensors[0].value. 이름에 점이나 대괄호가 든 멤버는 대괄호 안에 따옴표로 쓰며(['flow.rate']), 앞에 붙은 $.도 받아들입니다. 비어 있으면("페이로드 전체"로 표시) 페이로드 전체를 값으로 읽습니다. 잘못된 경로: "값 경로는 점으로 구분한 멤버와 대괄호 안의 배열 인덱스로 쓰십시오. 예: sensors[0].value" |
비어 있음 |
| 명령 토픽 | 쓰기가 발행되는 곳입니다. 비어 있으면 태그는 읽기 전용으로 남으며, 액세스가 쓰기를 포함하는 태그에는 꼭 있어야 합니다("쓰기 가능한 태그에는 쓰기를 발행할 토픽이 있어야 합니다."). 와일드카드는 넣을 수 없습니다("필터에는 아무것도 발행할 수 없으므로 명령 토픽에 + 또는 #를 넣을 수 없습니다."). 장비가 보고하는 토픽에서 지시를 기다리는 일은 드물기 때문에 이 칸은 따로 있습니다. | 비어 있음 |
| 페이로드 템플릿 | 쓰기가 발행하는 내용입니다. 쓴 값이 들어갈 자리에 {value}를 따옴표 밖에 정확히 한 번 둔 JSON이며, 예: {"setpoint": {value}}. 비어 있으면("값을 텍스트 그대로"로 표시) 값을 텍스트로 발행합니다. "페이로드 템플릿에는 쓴 값이 들어갈 자리에 이(가) 정확히 한 번 있어야 합니다." / "페이로드 템플릿은 JSON으로 쓰고, JSON 값이 들어갈 자리에 을(를) 따옴표 없이 두십시오." |
비어 있음 |
| 메트릭 | Sparkplug B. 탄생 인증서가 선언한 메트릭 이름입니다. 예: Inputs/Temperature. |
필수 |
데이터 형식은 Boolean, Int16, Int32, Int64, Float, Double, String, DateTime입니다. 읽기 전용인 와이어 주소 미리 보기는 토픽 뒤에 path, command, payload 가운데 해당하는 것을 붙인 것(plant/line1/temperature?path=sensors[0].value&command=plant/line1/setpoint)이거나 메트릭 이름입니다. 한 부분을 끝내 버리는 문자(%, ?, &, =, #, +, 공백)는 %XX로 씁니다.
읽기
세션은 구독한 토픽마다 마지막 메시지를 지니며, 태그는 거기에서 읽습니다.
| 상황 | 일반 MQTT 태그 | Sparkplug B 태그 |
|---|---|---|
| 값 | 토픽의 마지막 메시지입니다. 페이로드 전체를 텍스트로, 또는 값 경로에 있는 JSON 값을 태그의 형식으로 바꿉니다. | 엣지 노드의 마지막 탄생 메시지나 데이터 메시지에 있는 메트릭 값입니다. |
| 타임스탬프 | 메시지가 도착한 때입니다. 발행자가 보존한 메시지는 스테이션이 구독하자마자 첫 값을 줍니다. | 메트릭 자체의 타임스탬프입니다. |
| 아직 아무것도 받지 못함 | 태그는 기다립니다. 값도 오류도 없으며, 어느 드라이버든 첫 응답 전과 같습니다. 발행자가 보존하지 않는 토픽은 다시 발행될 때까지 값이 없습니다. 메시지 없이 지날 수 있는 최대 시간 (s)이 있으면 스테이션이 듣기 시작한 때부터 그 시간까지만 기다리고, 그 뒤에는 태그가 읽기에 실패합니다. | 탄생 인증서가 올 때까지 같습니다. 스테이션은 엣지 노드에 다시 알려 달라고 요청합니다. |
| 발행자가 조용해짐, 브로커는 연결됨 | 메시지 없이 지날 수 있는 최대 시간 (s)이 있으면 토픽에 그보다 오래 메시지가 없는 태그는 읽기에 실패하고, 응답하지 않은 장치에 대한 태그의 정책이 표시를 정합니다. 다음 메시지가 오면 돌아옵니다. 시간은 마지막 메시지(보존 메시지 포함)가 도착한 때부터 셉니다. 0이면 태그는 마지막으로 받은 값을 계속 지닙니다. | 해당 없음: 죽음 인증서가 알립니다. |
| 태그가 읽을 수 없는 메시지 | 그 태그의 읽기 실패이며 이유가 붙습니다. 빈 메시지, 값 경로가 있는데 JSON이 아닌 페이로드, 경로에 아무것도 없음, 형식에 담을 수 없는 값 등입니다. | 그 태그의 읽기 실패입니다. 탄생 인증서가 선언하지 않은 메트릭, 또는 형식에 담을 수 없는 값입니다. |
| 브로커에 연결할 수 없음 | 브로커의 모든 장치가 끊기고, 그 태그는 다른 장치의 태그와 똑같이 실패합니다. | 같습니다. |
| 죽음 인증서(NDEATH, DDEATH) | 해당하지 않습니다. | 엣지 노드와 그 장치들, 또는 그 장치 하나만이 다시 탄생할 때까지 값이 없습니다. 브로커의 다른 장치는 그대로 계속됩니다. |
Boolean 태그는 true나 false, 1이나 0, on이나 off를 받습니다. 정수 태그는 소수를 반올림해 받고 범위 밖의 수는 거부합니다. DateTime 태그는 ISO 8601 텍스트나 Unix 밀리초를 받습니다. String 태그는 텍스트를 그대로, JSON 객체나 배열은 원래의 JSON으로 받습니다. 부호 없는 형식의 Sparkplug B 메트릭은 범위 전체를 읽을 수 있도록 한 단계 넓은 부호 있는 형식으로 읽습니다(UInt8은 Int16, UInt16은 Int32, UInt32와 UInt64는 Int64).
쓰기
쓰기는 다른 모든 드라이버와 같은 경로를 지납니다. 쓰기 칸은 공학값을 받고, 원시값을 발행하기 전에 변환 단계를 거꾸로 거칩니다(Connector 참조).
| 태그 | 발행되는 것 | QoS | 쓰기가 알리는 것 |
|---|---|---|---|
| 일반 MQTT | 태그의 명령 토픽에 값을 텍스트 그대로(21.5, true, 텍스트 자체, ISO 8601 날짜), 또는 페이로드 템플릿에 JSON 값으로 넣어(숫자는 숫자로, 참거짓은 true나 false로, 텍스트는 따옴표로 감싸고 이스케이프해서) 발행합니다. |
1, 보존 안 함 | 브로커가 수신을 확인하면 완료입니다. MQTT 5 브로커가 거절하면 브로커의 이유와 함께 거부됩니다. 확인이 제때 오지 않으면 응답 없음입니다. |
| Sparkplug B | NCMD(엣지 노드의 메트릭) 또는 DCMD(그 뒤 장치의 메트릭)로 메트릭을 실어 보냅니다. 탄생이 준 별칭과 탄생이 선언한 형식을 씁니다. | 0, 보존 안 함. Sparkplug B 사양이 명령에 요구하는 대로입니다 | 보내는 순간 완료입니다. 엣지 노드는 새 값을 발행해 응답하고, 태그는 다음에 그 값을 읽습니다. |
브로커에 연결할 수 없는 동안, 또는 엣지 노드나 장치가 죽음을 알린 동안에는 쓰기가 끊김으로 거부되고 아무것도 보내지 않습니다. 탄생 인증서가 선언하지 않은 메트릭으로의 Sparkplug B 쓰기는 엣지 노드가 받지 않으므로 거부되며, 메트릭의 형식이 담을 수 없는 값도 마찬가지입니다. 쓰기는 절대 보존되지 않습니다. 보존된 설정값은 나중에 접속하는 모든 구독자에게 다시 적용되기 때문입니다.
발행
이 절은 발행 형식이 JSON일 때를 설명합니다. Sparkplug B는 다음 절에 있습니다.
브로커의 발행 카드에 있는 각 행은 그 토픽에 보존 메시지로 QoS 1로 발행되며, 브로커의 장치들이 쓰는 연결을 그대로 씁니다. 스테이션이 한 브로커에 두 번째 연결을 여는 일은 없습니다. 발행에만 쓰는 브로커에는 장치가 필요 없습니다. 브로커는 MQTT 드라이버 아래에 남고, 그 상태(연결하는 중…, 온라인, 연결할 수 없음)는 이 연결의 상태입니다. 사용 중이고 목록에 행이 있는 동안 발행하며, 따로 스위치는 없습니다.
| 신호원 | 메시지(JSON) |
|---|---|
| 태그 | {"value": 21.5, "quality": "good", "timestamp": "2026-10-04T12:30:15.250Z"}: 태그가 보여 주는 공학 값입니다. quality는 도착한 읽기면 good, 도착하지 않은 읽기면 bad이고 value는 null이며, 대체 값, 유지한 마지막 값, 더 이상 오지 않는 읽기면 uncertain입니다(마지막으로 발행한 값이 남습니다). 시각은 읽기의 타임스탬프이며 UTC입니다. |
| Logic 변수 | 같은 멤버입니다. 변수가 정상인 동안은 값과 good, 그렇지 않으면 null과 bad이며, 시각은 마지막 쓰기나 계산의 타임스탬프입니다. |
| 경보 | {"active": true, "acked": false, "state": 1, "priority": "High", "message": "Oven above 80 °C", "timestamp": "2026-10-04T12:30:15.250Z"}: 발생 여부, 확인 여부, 숫자로 된 state(0 정상, 1 발생 중이며 미확인, 2 발생 중이며 확인됨, 3 복귀했으며 미확인), 이름으로 된 우선순위(Critical, High, Medium, Low), 메시지(없으면 빈 값), 마지막 전이의 타임스탬프입니다. OPC UA 서버가 제공하는 것과 같습니다. |
값은 자기 JSON 형식으로 보내집니다. 숫자, true 또는 false, 텍스트, 날짜와 시각은 ISO 8601 텍스트입니다. JSON이 담지 못하는 숫자(NaN, 무한대)는 null로 보내집니다. 사용 안 함인 장치의 태그는 null과 bad를 발행합니다.
| 상황 | 발행되는 것 |
|---|---|
| 값이나 품질이 바뀜 | 그 행이며, 1초에 다섯 번 확인합니다. 같은 값으로 다시 읽은 태그는 다시 발행하지 않습니다. 타임스탬프만으로는 변화가 아닙니다. |
| 연결이 열리거나 다시 열림 | 모든 행을 지금 상태로 발행합니다. |
| 브로커가 멈춰 있음 | 아무것도 발행하지 않으며 대기열에서 기다리는 것도 없습니다. 브로커가 돌아오면 모든 행을 그 순간의 상태로 발행합니다. |
| 브로커가 메시지를 거부하거나 확인하지 않음 | 30초 뒤에 다시 시도합니다. 진단 로그의 Connector 영역, 구성 요소 MQTT publication에 처음 한 번, 계속되는 동안에는 몇 분마다 요약으로 기록됩니다. |
| 신호원이 삭제됨 | 더 이상 발행하지 않습니다. 브로커는 마지막으로 보관한 메시지를 그대로 둡니다. |
| 행이 삭제됨 | 더 이상 발행하지 않습니다. 보존 메시지는 그곳에 다른 것이 발행될 때까지 토픽에 남습니다. |
스테이션은 발행하는 것을 읽기만 하며, 그것을 위해 무엇도 계산하지 않습니다. 태그의 마지막 읽기, 변수의 값, 경보의 상태입니다. 읽기 전용인 행의 토픽은 구독하지 않으므로, 다른 시스템이 거기에 발행한 메시지는 스테이션에 닿지 않습니다. 읽기와 쓰기인 행은 쓰기 토픽에서 값을 받습니다(되쓰기). 에이전트는 mqtt_publish_list로 목록을 읽고, mqtt_publish_upsert와 mqtt_publish_delete로 바꿉니다(도구).
mqtt_publish_upsert(brokerId: "<id from mqtt_broker_list>", source: "Connector.Simulated.Oven.Temperature")
mqtt_publish_upsert(brokerId: "<id from mqtt_broker_list>", source: "Alarms.Oven.HighTemperature", topic: "plant/oven/alarms/high")
mqtt_publish_upsert(id: "<id from mqtt_publish_list>", access: "ReadAndWrite")
mqtt_publish_list()
Sparkplug B로 발행
발행 형식을 Sparkplug B로 두면 브로커는 같은 목록을 Sparkplug B 사양대로, 스테이션을 엣지 노드로 삼아 발행합니다. Ignition의 MQTT Engine 같은 Sparkplug B 호스트는 스테이션을 그 그룹과 엣지 노드 아래에, 각 장치를 그 아래에, 각 메트릭을 형식과 함께 나열합니다. 손으로 만드는 매핑은 필요 없습니다. 연결은 JSON일 때처럼 브로커의 장치들이 쓰는 연결입니다.
| 이름 | 무엇인지 |
|---|---|
| 그룹 | 그룹 ID입니다. 비어 있는 동안은 GanterLab입니다. |
| 엣지 노드 | 스테이션 이름이며, /, +, #(Sparkplug B ID에 쓸 수 없는 세 문자)는 각각 _가 됩니다. |
| 장치 | 태그 행이 있는 Connector의 각 장치로, 같은 규칙으로 이름이 붙습니다. |
| 태그의 메트릭 | 태그 이름이며, 그 장치 위에 있습니다. |
| 변수의 메트릭 | Logic/<folders>/<variable>이며, 엣지 노드 위에 있습니다. |
| 경보의 메트릭 | 엣지 노드 위 Alarms/<folders>/<alarm>/ 아래에 다섯 개입니다. Active와 Acked(Boolean), State(숫자로 0 정상, 1 발생 중이며 미확인, 2 발생 중이며 확인됨, 3 복귀했으며 미확인), Priority와 Message(텍스트)입니다. |
이름 안의 /는 _가 되므로 단계가 되는 것은 폴더뿐입니다. 이름이 같아지는 두 장치나 두 메트릭에는 원래 이름 순서대로 _2, _3이 붙습니다. 행은 토픽을 그대로 갖고 있습니다. Sparkplug B에서는 그 토픽에 아무것도 발행하지 않으며, 브로커를 JSON으로 되돌리면 목록은 다시 그곳에 발행합니다.
| 메시지 | 언제 |
|---|---|
| NDEATH(엣지 노드의 죽음) | 연결이 열릴 때마다 연결의 마지막 유언으로 브로커에 넘겨, 스테이션이 끊기면 브로커가 발행합니다. 스테이션도 발행을 멈추기 전에 직접 발행합니다. 브로커를 JSON으로 되돌렸을 때, 사용 안 함으로 바꾸거나 삭제했을 때, 목록을 비웠을 때, 그룹이나 스테이션 이름을 바꿨을 때, 런타임을 멈췄을 때입니다. |
| NBIRTH(엣지 노드의 탄생) | 연결이 열릴 때마다, 호스트가 다시 알려 달라고 요청할 때(Node Control/Rebirth), 변수나 경보가 들어오거나 빠지거나 이름이 바뀔 때입니다. 엣지 노드의 모든 메트릭을 현재 값으로, bdSeq와 Node Control/Rebirth와 함께 담습니다. |
| DBIRTH(장치의 탄생) | 각 NBIRTH 뒤에 모든 장치에 대해, 그리고 목록에 들어온 장치에 대해 보냅니다. 장치의 모든 태그를 현재 값으로 담습니다. |
| NDATA, DDATA | 1초에 다섯 번, 값이나 품질이 바뀐 메트릭을 보냅니다. 엣지 노드에 하나, 장치마다 하나의 메시지입니다. |
| DDEATH(장치의 죽음) | 장치의 마지막 행이 목록에서 빠질 때, 그리고 태그가 바뀐 장치가 다시 탄생하기 전에 보냅니다. |
NDEATH를 뺀 모든 메시지는 QoS 0으로, 보존하지 않고 나갑니다. 시퀀스 번호 seq는 NBIRTH마다 0에서 시작해 그 뒤의 메시지마다 255까지 세고 다시 처음으로 돌아갑니다. bdSeq는 연결을 세므로, 한 연결의 NBIRTH와 NDEATH는 같은 번호를 갖습니다. 브로커가 멈춰 있는 동안에는 아무것도 대기열에 쌓지 않습니다.
| 신호원의 형식 | Sparkplug B 형식 |
|---|---|
Boolean |
Boolean |
SByte, Byte |
Int8, UInt8 |
Int16, UInt16 |
Int16, UInt16 |
Int32, UInt32 |
Int32, UInt32 |
Int64, UInt64 |
Int64, UInt64 |
Float, Double |
Float, Double |
String |
String |
DateTime |
DateTime |
Guid, ByteString |
UUID, Bytes |
태그는 태그 자신의 형식으로, 변수는 OPC UA 서버가 제공하는 형식으로 발행합니다(정수는 Int64, 실수는 Double, 표시용 값은 텍스트). 각 메트릭은 품질을 속성 Quality에 담습니다. Sparkplug B 호스트가 읽는 관례로, 192는 양호, 64는 불확실(읽기가 끊겼을 때는 마지막으로 발행한 값), 0은 불량(이때 메트릭은 값이 없습니다)입니다.
| 명령 | 스테이션이 하는 일 |
|---|---|
NCMD Node Control/Rebirth |
NBIRTH와 모든 DBIRTH를 현재 값으로 다시 발행합니다. |
| 읽기와 쓰기인 행의 메트릭을 가리키는 NCMD나 DCMD | 되쓰기처럼 값을 신호원에 씁니다. 명령이 도착한 순서대로, 출처 MQTT <broker name>으로 진단 로그에 기록됩니다. |
| 그 밖의 메트릭, 값이 없는 명령, 브로커가 보존해 두었다가 넘긴 명령 | 아무것도 쓰지 않습니다. 진단 로그의 Connector 영역, 구성 요소 MQTT publication에 기록됩니다. |
스테이션은 호스트가 언제든 다시 알려 달라고 요청할 수 있도록 엣지 노드로 오는 명령은 항상 듣고, 장치로 오는 명령은 그 장치의 행 중 하나가 읽기와 쓰기인 동안에만 듣습니다. 브로커를 Sparkplug B로 바꾸면, 브로커가 엣지 노드의 유언을 갖도록 그 연결이 한 번 다시 열립니다. 브로커의 장치들은 다른 재연결처럼 이를 넘깁니다. 스테이션은 엣지 노드이며 기본 호스트 애플리케이션이 아닙니다. 탄생하기 전에 호스트의 STATE 메시지를 기다리지 않습니다.
mqtt_broker_upsert(id: "<id from mqtt_broker_list>", publishFormat: "SparkplugB", sparkplugGroupId: "Plant1")
mqtt_publish_list()
되쓰기
발행 카드의 행을 읽기와 쓰기로 두면 그 행은 쓰기 토픽(행의 토픽 뒤에 /set을 붙인 것)에서 값을 받습니다. 예를 들어 plant/oven/setpoint를 읽는 클라우드 대시보드는 새 설정값을 plant/oven/setpoint/set으로 보냅니다. 스테이션은 Modbus 서버나 OPC UA 서버의 클라이언트가 읽기와 쓰기로 표시된 행에 쓰는 것과 같은 방식으로 그것을 씁니다.
| 상황 | 일어나는 일 |
|---|---|
| 행을 읽기와 쓰기로 두었을 때 | 스테이션은 브로커의 장치들이 쓰는 연결로 그 쓰기 토픽을 QoS 1로 구독하고, 그 연결이 열릴 때마다 다시 구독합니다. 읽기 전용인 행은 구독하지 않으므로 그 쓰기 토픽의 메시지는 스테이션에 닿지 않습니다. |
| 쓰기 토픽에 메시지가 왔을 때 | {"value": 65} 또는 값 그대로(65, true, 레시피 A)를 메시지가 온 순서대로 신호원에 씁니다. 태그에는 운전원의 쓰기와 같은 경로로, 내부 값 변수에는 그대로 씁니다. JSON 숫자, true나 false, JSON 텍스트는 담고 있는 값으로 오며, JSON이 아닌 것은 텍스트로 읽습니다. 값은 다른 쓰기와 마찬가지로 신호원의 형식으로 변환되며, 그 형식이 담을 수 없는 값은 거부됩니다. |
| 메시지에 값이 없을 때 | 아무것도 쓰지 않습니다. 빈 메시지, null, value가 없는 JSON 객체, 배열입니다. |
| 브로커가 보존해 둔 메시지를 넘겨줄 때 | 아무것도 쓰지 않습니다. 브로커는 스테이션이 구독할 때 그것을 넘겨주지만, 한 시간 전에 남겨 둔 설정값은 지금 누군가가 보내는 값이 아닙니다. 스테이션이 듣는 동안 발행된 값은 보존 여부와 상관없이 씁니다. |
| 신호원이 더 이상 쓰기를 받지 않을 때 | 아무것도 쓰지 않습니다. 읽기 전용으로 되돌린 태그, 삭제된 변수입니다. |
| 행을 읽기 전용으로 되돌리거나, 토픽을 바꾸거나, 삭제했을 때, 또는 브로커를 사용 안 함으로 했을 때 | 스테이션은 곧 그 쓰기 토픽을 듣지 않으며, 그 사이에 온 메시지는 아무것도 쓰지 않습니다. |
진단 로그는 운전원의 쓰기처럼 각 쓰기를 Connector 영역에 MQTT <브로커 이름> 출처로 기록합니다. 쓰지 않은 메시지는 진단 로그의 Connector 영역, 구성 요소 MQTT publication에 처음 한 번, 반복되는 동안에는 몇 분마다 요약으로 기록됩니다.
보호 수단은 브로커의 사용자 이름과 비밀번호뿐입니다. 브로커가 쓰기 토픽에 발행하도록 허용한 사람은 누구나 그 신호원을 바꿀 수 있고, 다른 사람과 함께 쓰는 클라우드 브로커에서는 공장 밖의 사람도 포함됩니다. 브로커에서 대시보드 계정에는 필요한 토픽만 허용하십시오. Sparkplug B인 브로커에서는 같은 행이 쓰기 토픽 대신 Sparkplug B 명령(NCMD, DCMD)을 받습니다(Sparkplug B로 발행).
"C:\Program Files\mosquitto\mosquitto_pub" -h localhost -u dashboard -P <password> -t plant/oven/setpoint/set -m 65
보안
TLS 사용에서는 브로커의 인증서를 두 가지 중 한 방법으로 받아들입니다. 인증서 체인과 호스트 이름이 이 컴퓨터의 다른 HTTPS 연결과 똑같이 Windows 인증서 저장소로 검증되거나, 이 드라이버 페이지의 현장 장비 접근에서 바로 그 인증서를 승인한 경우입니다. 자체 인증 기관이 발급한 인증서를 쓰는 브로커는 그 인증 기관을 Windows 저장소에 설치하면 신뢰되며, 자체 서명 인증서를 쓰는 브로커는 그 인증서를 승인하면 아무것도 설치할 필요가 없습니다. 해지는 확인하지 않으며, 보지 않은 인증서를 받아들이는 것은 없습니다. 모르는 인증서는 거부되고, 브로커는 이유와 함께 연결할 수 없음으로 남으며, 그 장치는 승인을 기다립니다. 비밀번호는 TLS 연결 안으로 오갑니다. TLS가 없으면 카드의 경고대로 평문으로 오갑니다.
현장 장비 접근
자체 서명했거나 자체 인증 기관이 발급한 인증서를 쓰는 브로커는 Windows에 설치된 어떤 루트도 보증하지 않는 인증서를 내놓습니다. 그 루트를 이 컴퓨터에 설치할 필요는 없습니다. TLS 사용에서는 첫 연결이 거부되고, 브로커는 이유와 함께 연결할 수 없음으로 남으며, 그 장치는 트리와 각 페이지에서 인증서 승인 대기 중으로 표시되고, 그 페이지의 인증서 검토 단추가 이 카드를 그 인증서 위치에서 엽니다. 인증서는 MQTT 드라이버 페이지 끝의 현장 장비 접근에서 결정을 기다립니다. OPC UA 드라이버 페이지에 있는 것과 같은 카드입니다.
| 그룹 | 보여 주는 것 | 할 수 있는 일 |
|---|---|---|
| 승인 대기 중 | 거부된 인증서마다 인증서가 내세우는 이름 아래에, SHA-256 지문, 그 인증서를 만난 브로커 주소, 마지막 시도 시각과 횟수, 세부 정보(주체, 발급자, 도메인 이름, 유효 기간)가 나옵니다. 장치의 인증서 검토로 연 인증서에는 검토하도록 선택됨 표시가 붙습니다. | 승인하면 세션의 다음 연결 시도부터 그 인증서를 받아들입니다. 차단하면 여기에 다시 올리지 않고 계속 거부합니다. 대기 중인 인증서 모두 버리기는 아무것도 승인하거나 차단하지 않고 목록을 비웁니다. |
| 승인된 현장 장비 | 승인했거나 가져온 인증서가 누가 언제 결정했는지, 각 인증서를 마지막으로 만난 브로커 주소와 함께 나옵니다. | 승인 철회는 브로커의 세션을 닫고 그 인증서를 목록으로 되돌립니다. 인증서 가져오기는 이미 가진 공개 인증서 파일(.der, .cer, .crt, .pem)을 첫 연결 전에 승인합니다. |
| 차단된 현장 장비 | 차단한 인증서가 나옵니다. 차단한 인증서는 Windows가 신뢰하더라도 거부됩니다. | 차단 해제는 승인하지 않고 인증서를 목록으로 되돌립니다. |
승인하기 전에 브로커를 관리하는 담당자와 함께 지문을 확인하십시오. 승인은 그 인증서 하나만, 그것도 유효 기간 안에서만 받아들입니다. 승인은 Windows에 없는 루트와 인증서에 적힌 이름을 대신하므로, IP 주소로 접속하는 브로커도 인증서에 다른 호스트가 적혀 있어도 연결되며, 인증서의 다른 점은 아무것도 느슨해지지 않습니다. 승인한 인증서의 주소에서 브로커가 다른 인증서를 내놓으면 그 장치는 읽기를 멈추고, 새 인증서가 여기에서 기다리며, 스테이션이 검토 단추와 함께 "인증서가 바뀜: <이름>"을 알립니다. 장치 검색 카드에서 하는 브로커 검색도 같은 결정을 따릅니다. Windows가 이미 신뢰하는 인증서는 예전처럼 받아들여지고 여기에는 나타나지 않습니다. 자동으로 승인되는 것은 없습니다.
브로커의 원인은 이름 없는 TLS 오류 대신 이유를 말합니다. "<호스트>:<포트>의 브로커 인증서(지문의 앞 16자)가 MQTT 드라이버 페이지의 현장 장비 접근에서 승인을 기다립니다. 승인하면 읽기가 시작됩니다." 차단한 인증서라면 "…은 이 스테이션에서 차단되었습니다. MQTT 드라이버 페이지의 현장 장비 접근에서 검토하십시오."라고 읽힙니다. 유효 기간을 벗어났거나, 해지되었거나, 서명이 깨진 인증서는 그 이유로 거부되고 목록에 오르지 않습니다. 승인해도 건전해지지 않기 때문입니다.
결정은 스테이션 데이터 폴더의 ua\pki\mqtt에 저장되며 다시 시작해도 남습니다. 동작 단추는 Connector를 구성할 수 있는 역할에만 그려지고, 스테이션 자신의 창에서만 동작합니다. 다른 기기의 브라우저는 카드를 읽기만 하고 바꾸지 못하며, 에이전트 도구는 인증서를 승인하지 않습니다(connector_browse는 브로커의 장치를 awaitingCertificate로 알립니다). 목록에는 승인 대기 중인 인증서를 100개까지 둡니다. 가득 차면 새 인증서는 계속 거부되지만 목록에 오르지 않으며, 카드가 그렇다고 알립니다.
브로커 준비
브로커는 스테이션 컴퓨터의 연결을 받아야 하고, 스테이션의 로그인을 받아야 합니다. 가장 흔한 브로커인 Eclipse Mosquitto 2는 출하 상태에서 둘 다 하지 않습니다. mosquitto.conf에 listener가 없으면 자기 컴퓨터에서만 수신 대기하고, listener가 생기면 사용자 이름 없는 클라이언트를 거부합니다. MQTT는 어떤 브로커가 응답했는지 알려 주지 않으므로, 스테이션은 Mosquitto를 흔한 경우로만 들 뿐 단정하지 않습니다.
| 브로커의 응답 | 브로커 페이지가 알려 주는 것 | 바꾸는 방법 |
|---|---|---|
| 그 컴퓨터가 포트를 거부함 | 브로커가 자기 컴퓨터의 연결만 받습니다 | mosquitto.conf에 listener와 포트 줄(listener 1883)을 넣고 브로커를 다시 시작한 뒤, 그 컴퓨터의 방화벽에서 포트를 허용 |
| 사용자 이름 없는 클라이언트를 거부함 | 브로커가 사용자 이름 없는 클라이언트를 받지 않습니다 | 브로커 연결 카드의 사용자 이름과 비밀번호에 브로커 계정을 넣습니다. Mosquitto 2에서는 그 계정을 mosquitto_passwd로 만들고 mosquitto.conf의 password_file로 지정하거나, allow_anonymous true로 익명 클라이언트를 들여보냅니다 |
| 사용자 이름 또는 비밀번호를 거부함 | 브로커 자신의 거부로, 브로커 연결 카드의 사용자 이름과 비밀번호를 가리킵니다 | 브로커나 카드의 계정 |
처음 두 가지는 브로커 페이지에서 영어 오류 대신 이 절차와 포트와 함께 알려 줍니다. 그 아래 장치들은 계속 브로커를 가리킵니다. 세션이 연결되면 이 알림은 저절로 사라집니다. 트리의 표시와 저널에는 영어 원인이 남고, 그 끝에 같은 Mosquitto 절차가 붙습니다.
브로커 설치
스테이션에는 접속할 브로커가 필요하고, 장비에도 필요합니다. 없다면 Eclipse Mosquitto가 Windows 서비스로 실행되는 작은 브로커입니다.
mosquitto.org의 다운로드 페이지에서 Windows용 설치 프로그램을 받아 실행합니다.
C:\Program Files\mosquitto에 Mosquitto Broker 서비스가 설치됩니다.처음 상태의 Mosquitto는 자신이 실행되는 컴퓨터 안에서만 응답합니다. 네트워크의 장비를 받아들이려면 그 폴더의
mosquitto.conf에 리스너와 비밀번호 파일을 더합니다.listener 1883 password_file C:\Program Files\mosquitto\passwd스테이션과 장비가 쓸 계정으로 파일을 만듭니다(명령이 비밀번호를 묻습니다).
"C:\Program Files\mosquitto\mosquitto_passwd" -c "C:\Program Files\mosquitto\passwd" station관리자 명령 프롬프트에서 서비스를 다시 시작하고, Windows Defender 방화벽에서 장비 네트워크로부터 들어오는 TCP 포트 1883을 허용합니다.
net stop mosquitto net start mosquitto브로커 페이지에서, 브로커가 스테이션과 같은 컴퓨터에서 실행되면 호스트에
localhost를, 아니면 그 컴퓨터의 주소를 넣고, 포트 1883과 만든 계정을 넣은 다음 사용을 누릅니다.
장비를 연결하기 전에 일반 태그를 시험하려면, 같은 폴더에서 보존되는 시험 값을 발행하고 태그의 토픽을 그곳에 맞춥니다.
"C:\Program Files\mosquitto\mosquitto_pub" -h localhost -u station -P <password> -t plant/line1/temperature -m 21.5 -r
알아 둘 한계
- MQTT 드라이버는 클라이언트이지 브로커가 아닙니다. 장비와 스테이션은 브로커에 접속하며, 그 브로커는 스테이션 자체의 MQTT 브로커일 수도 있고 다른 브로커일 수도 있습니다.
- 브로커의 발행 카드는 JSON이나 Sparkplug B 중 하나로 나가며, 둘을 동시에 내보내지 않습니다. Sparkplug B일 때 스테이션은 엣지 노드이지 기본 호스트 애플리케이션이 아니며, 별칭, 템플릿, 이력 값은 쓰지 않습니다.
- 스테이션은 Sparkplug B 호스트 애플리케이션이 아니며 STATE 메시지를 발행하지 않습니다. 발행하기 전에 기본 호스트를 기다리도록 설정된 엣지 노드는 조용히 남습니다.
- 일반 MQTT는 조용해진 발행자에 대해 아무것도 알리지 않습니다. 일반 태그는 브로커 연결이 유지되는 동안 마지막으로 받은 값을 도착 시각과 함께 계속 지닙니다. 단, 장치에 메시지 없이 지날 수 있는 최대 시간 (s)이 정해져 있으면 그렇지 않습니다. 값이 바뀔 때만 발행되는 토픽은 조용해진 발행자와 그대로인 값을 구별하지 못하므로 그 장치는 0으로 둡니다. Sparkplug B는 죽음 인증서로 그것을 알립니다.
- 세션은 깨끗한 상태로 시작합니다. 스테이션이 접속하지 않은 동안 발행된 것은 다시 오지 않으며, 태그에 값을 되돌려 주는 것은 토픽의 보존 메시지입니다.
- 태그는 토픽 하나와 그 안의 값 하나를 읽으며 필터는 읽지 않습니다. 배열, 데이터 세트, 템플릿, 속성 세트인 Sparkplug B 메트릭은 읽지 않습니다.
- TCP만 쓰며 TLS는 선택입니다. WebSocket 위의 MQTT, 클라이언트 인증서, MQTT 3.1.1보다 오래된 브로커는 지원하지 않습니다.
- 장치를 다른 브로커로 옮길 수 없습니다. 다른 브로커 아래에 만들고 옛 장치를 삭제하십시오.