이력
- 이력을 저장하는 변수에 값을 써서 기록을 만듭니다.
- 지난 1시간의 Raw 이력을 읽습니다.
- 한 번에 받을 값의 개수를 제한하고 연속 지점(continuation point)으로 나머지를 받거나 해제합니다.
준비물
섹션 제목: “준비물”- 실습 환경의
apps패키지와 환경 변수OPCUA_APPS - 터미널 한 개
1. 시뮬레이터 실행과 연결
섹션 제목: “1. 시뮬레이터 실행과 연결”"$OPCUA_APPS/bin/pdcomm-opcua-headless"{"action":"server_start"}{"action":"connect"}2. 값 기록하기
섹션 제목: “2. 값 기록하기”Simulator.Double은 값을 쓸 때마다 이력에 기록됩니다. 값 세 개를 씁니다.
{"action":"write","node":"ns=2;s=Simulator.Double","type":"Double","value":1.5}{"action":"write","node":"ns=2;s=Simulator.Double","type":"Double","value":2.5}{"action":"write","node":"ns=2;s=Simulator.Double","type":"Double","value":3.5}각 응답은 {"ok":true,"result":{"good":true,...}}입니다.
3. Raw 이력 읽기
섹션 제목: “3. Raw 이력 읽기”기간을 지정하지 않으면 지금부터 1시간 전부터 1분 뒤까지 읽습니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double"}{"ok":true,"result":{"continuation":null,"good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","values":[{"good":true,"source_time":1791997613205,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"source_time":1791997613335,"status":"Good (0x00000000)","type":"Double","value":1.5},{"good":true,"source_time":1791997613339,"status":"Good (0x00000000)","type":"Double","value":2.5},{"good":true,"source_time":1791997613342,"status":"Good (0x00000000)","type":"Double","value":3.5}],"window":{"end":1791997673344,"start":1791994013344}}}첫 값 0.0은 서버를 시작할 때 기록한 초기값입니다. window는 실제로 요청한 기간(Unix 밀리초)입니다. 다른 기간을 읽으려면 start와 end를 Unix 밀리초로 지정합니다.
4. 연속 지점으로 나눠 받기
섹션 제목: “4. 연속 지점으로 나눠 받기”max로 한 번에 받을 값을 2개로 제한합니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","max":2}{"ok":true,"result":{"continuation":"25b15bec55060e062202f744cc176951d2dd625ee5c16f89d693cafbc31b8cd8","good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","values":[{"good":true,"source_time":1791997613205,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"source_time":1791997613335,"status":"Good (0x00000000)","type":"Double","value":1.5}],"window":{"end":1791997673348,"start":1791994013348}}}값이 더 있으므로 continuation에 연속 지점이 있습니다. 받은 연속 지점을 그대로 넣어 나머지를 받습니다. 아래 값을 자신의 값으로 바꿉니다. 시뮬레이터가 처음 요청의 기간과 max를 다시 쓰므로 연속 지점만 지정하면 됩니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","continuation":"25b15bec55060e062202f744cc176951d2dd625ee5c16f89d693cafbc31b8cd8"}{"ok":true,"result":{"continuation":null,"good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","values":[{"good":true,"source_time":1791997613339,"status":"Good (0x00000000)","type":"Double","value":2.5},{"good":true,"source_time":1791997613342,"status":"Good (0x00000000)","type":"Double","value":3.5}],"window":{"end":1791997673348,"start":1791994013348}}}continuation이 null이면 모든 값을 받은 것입니다.
5. 연속 지점 해제
섹션 제목: “5. 연속 지점 해제”나머지 값이 필요 없으면 연속 지점을 해제해 서버 자원을 돌려줍니다. 새 연속 지점을 받습니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","max":2}받은 연속 지점에 "release":true를 붙입니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","continuation":"1ea43b51cfb7c23dc05a68b65c79eb93c4cdc05dea99375578f729ffcd7c4a4c","release":true}{"ok":true,"result":{"continuation":null,"good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","values":[],"window":{"end":1791997673356,"start":1791994013356}}}해제한 연속 지점은 다시 쓸 수 없습니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","continuation":"1ea43b51cfb7c23dc05a68b65c79eb93c4cdc05dea99375578f729ffcd7c4a4c"}{"ok":true,"result":{"continuation":null,"good":false,"node":"ns=2;s=Simulator.Double","status":"BadContinuationPointInvalid (0x804A0000)","values":[],"window":{"end":1791997673356,"start":1791994013356}}}6. 값이 없는 기간과 이력이 없는 노드
섹션 제목: “6. 값이 없는 기간과 이력이 없는 노드”1970년 1월 1일의 첫 1초처럼 값이 없는 기간은 GoodNoData입니다.
{"action":"history_read","node":"ns=2;s=Simulator.Double","start":0,"end":1000}{"ok":true,"result":{"continuation":null,"good":true,"node":"ns=2;s=Simulator.Double","status":"GoodNoData (0x00A50000)","values":[],"window":{"end":1000,"start":0}}}Simulator.Int32는 있는 변수지만 이력을 저장하지 않습니다. 이 변수의 이력을 읽으면 BadHistoryOperationUnsupported입니다.
{"action":"history_read","node":"ns=2;s=Simulator.Int32"}{"ok":true,"result":{"continuation":null,"good":false,"node":"ns=2;s=Simulator.Int32","status":"BadHistoryOperationUnsupported (0x80720000)","values":[],"window":{"end":1792000524047,"start":1791996864047}}}없는 노드(Simulator.Missing)를 읽으면 BadNodeIdUnknown입니다.
{"action":"history_read","node":"ns=2;s=Simulator.Missing"}{"ok":true,"result":{"continuation":null,"good":false,"node":"ns=2;s=Simulator.Missing","status":"BadNodeIdUnknown (0x80340000)","values":[],"window":{"end":1792000524052,"start":1791996864052}}}7. 정리
섹션 제목: “7. 정리”{"action":"shutdown"}Simulator.Counter도 이력을 저장합니다. 서버를 시작한 직후 같은 밀리초에 두 값이 기록되므로 첫 값의status가Good (0x00000408)(HistorianExtraData)로 보일 수 있습니다. 이력 접근에서 설명합니다.- 서비스가 처리되었지만 노드의 결과가 Bad이면 응답의
ok는 true이고good이 false입니다. - GUI에서는 History 탭의 **Read raw history (last hour)**가 같은 요청을 보냅니다.