현재 진행중인 프로젝트도 지난번의 에코넷을 이용한 중계 기능과 비슷하다. 이번에는 에코넷라이트의 기기가 아닌 모드버스(ModBus) 프로토콜을 사용하는 기기로부터 여러 데이터를 읽어서 MQTT에 publish 하거나 반대로 설정 값을 바꾸는 프로그램을 자바로 작성하는 일이다.

MQTT로 데이터를 보내거나 받는 PubSub 모델은 지난 프로젝트를 통해서 기본적인 개념만 익히고 사용했지만 만들어야 하는 기능 자체가 단순해서 그 기본으로 충분했다. 이번에도 마찬가지여서 MQTT에 대한 부담은 거의 없었다. 대신 생전 처음 들어보는 Modbus라는 녀석은 난감하기만 했다. 유튜브나 블로그를 검색하면서 개념만 익히려고 했지만 PLC? 같은 하드웨어를 다루는 사람들의 어려운 이야기가 대부분이라 기초부터 이해하기에는 효율이 좋지 못하다고 생각했다. 무엇보다 이번 프로젝트에서 내게 주어진 시간이 많지 않아서 기술의 배경까지 익히는 것은 아쉽지만 포기해야할 상황이다.

그래서 먼저 Modbus를 사용하는 기기로에 연결해서 데이터를 주고 받을 수 있는 모드버스 클라이언트 라이브러리를 검색했다. 깃헙에서는 Modbus4j라는 프로젝트가 있었지만 설명이 많이 없어서 친절하지 않았다. 파이썬으로 만든 프로젝트에는 매우 쓸만해보이는 것이 있었지만 구현 언어가 자바로 거의 굳어 있기 때문에 아쉽지만 포기해야 했다. 그래서 마지막으로 고르게 된 것이 EasyModbus(http://easymodbustcp.net/en/)라는 라이브러리이다.

자바 버전 외에도 닷넷과 파이썬 버전도 가지고 있는 회사?로 보였는데 기능적으로 다양하지는 않았지만 이번 과제를 수행하는 데에는 부족함이 없어보였다.

코일이랄지 레지스트리와 같은 개념은 넣어두고, 구현 대상의 모드버스 디바이스는 Enapter사의 수소전지인데 문제는 에코넷 프로젝트에서처럼 프로토콜의 에뮬레이터 또는 시뮬레이터를 찾을 수가 없었다. 에코넷 에뮬레이터에는 각종 에코넷 기기들이 거의 다 등록되어 있었는데 모드버스는 디바이스(에코넷에서는 대부분 가정용 가전이긴 했다.)의 범위가 넓어서 에코넷보다 범용적인 프로토콜로 보인다.

수소전지의 에뮬레이터는 없었지만 다행이 범용 모드버스 시뮬레이터는 찾을 수 있었다. 내부 데이터는 죄다 비어 있는 다시 말해 내가 일일이 값을 넣어둬야 데이터를 가져오는 테스트를 할 수 있었다.

이더넷을 통해 TCP로 모드버스 기기에 연결하는 것은 간단했다. IP주소와 포트 번호로 connect()를 호출하는 것으로 끝. 데이터를 HoldingRegister와 InputRegister에서 가져오는 것도 각종 read 메서드로 할 수 있었지만 반환 값의 타입이 모두 int[]인 것은 좀 껄끄러웠다. 하나의 레지스터는 2바이트로 이루어져 있는데 기기에 저장된 각각의 유의미한 데이터가 2바이트뿐 아니라 4, 8, 16바이트 등 다양한 길이로 구성돼 있었다.

실제 데이터의 타입으로는 Uint16, Uint32, Uint64, Uint128, Float32, Boolean이 사용된다. 아주 오래전 C언어를 배우던 시절이 떠오르는 것이다. 요즘같이 파이썬이나 자바스크립트처럼 엄격한 타이핑을 필요로 하지 않는 언어가 얼마나 편리한지 새삼 느낄 수 있었다.(성능 문제는 빼고!)

자바도 타입을 strict하게 사용하므로 정수 배열 int[]을 최종 타입인 Uint32등으로 변환하기 위해서는 타입의 이해도 필요하지만 변환 메서드도 조사해야만 했다. 바이트, 바이너리 단위까지 가면 왜인지 모르겠지만 긴장이 된다. 16진수만 나와도 겁이 나는 건 참 안쓰러운 버릇이다.

학부 때에는 주로 int와 String만 썼고 long은 데면데면한 녀석이었다. 하지만 이번에는 매순간을 마주해야 했다. 예를 들어 2개의 레지스터에서 가져올 수 있는 데이터는 4바이트이므로 int 타입 변수에 저장하면 될 것 같지만 위에서 적은 것처럼 Uint32 즉 Unsigned Int이므로 MSB의 역할 차이에 의해 가져온 데이터를 그냥 int 타입 변수에 넣으면 실제 표현하고자 하는 데이터와는 다른 값이 되어 버린다. 그래서 read()로 받은 int[] 을 바이트 배열로 변환하고 그로부터 Unsigned 값이나 단순 문자열, 16진수, IP주소, 맥어드레스, 비트마스크, 제조사 커스텀 데이터 형식으로 변환하는 처리를 만드는 중이다.