본문 바로가기
IoT

mqtt 서버 끼리 연동하기 (외부/내부 따로 운영 + zigbee2mqt / External Bridge)

by ㅋㅋ잠자 2022. 2. 16.
반응형

안녕하세요. 도정진입니다.

 

제가 MQTT 연동을 편하게 하기 위해서 내부망에서는 익명 로그인을 허용하도록 설정하여 사용중이였습니다.

그런데, 외부 서버와 연동할 일이 생겨서 어쩔 수 없이 비번을 걸어야 했는데요.

 

비번을 걸기에는 설정을 여러가지로 바꾸어야하는 문제가 있어서 아래와 같이 설정을 진행했습니다.

 

참고 문서 : http://www.steves-internet-guide.com/mosquitto-bridge-configuration/

 

1. 개요

내부망 MQTT 가 있고, 외부망 전용 MQTT 가 2개 있습니다.

내부망은 아이디 비번이 없는 상태이고, 외부망은 아이디 비번이 있는 상황이며, 두 서버 모두 한 호스트에 돌고 있고 192.168.0.123 이라는 아이피를 할당 받습니다.

 

내부망은 192.168.0.123:1883 로 동작하고, 외부망용은 192.168.0.123:11883 으로 동작합니다.

그럼 공유기에서는 11883 포트만 포워딩하면 외부에서 제 쪽으로 MQTT 토픽을 보낼 수 있습니다.

 

그럼, 실제로 HA 에서는 두 MQTT 서버에 연동이 불가능 하게 되어 있는데요. 이럴 때에는, MQTT 서버 브릿지를 사용하시면 됩니다.

 

일단 다수의 서버가 메시지들을 공유하려고 할 때에는 조금 어려움이 있지만, 2개가 연동할 때에는 그렇게 어려움이 있지 않습니다.

 

그러면 로컬 MQTT <---> 외부 MQTT 이렇게 연동이 되어야 하고, 전체적인 그림은 아래와 같이 됩니다.

 

다른 위치의 장치에서, 제 외부 MQTT 서버로 메시지를 보냅니다.

그 메시지는 다시 로컬 MQTT 와 공유됩니다.

 

2. 설정 방법 - 1) mqtt 서버 하나 더 추가

먼저 로컬로 돌아가고 있는 MQTT 서버는 익명이고, 1883 포트로 동작 중입니다.

컨테이너로 하나 더 돌리기 위해서 아래 명령을 입력하여 구동시킵니다.

docker run -dit -p 11883:1883 --name mqtt_wan --restart unless-stopped -v /opt/mqtt:/mosquitto:rshared eclipse-mosquitto

기본적인 설정파일이 생기지 않기 때문에 아래와 같이 설정 파일을 샘플로 기입합니다.

root@debian:~# cd /opt/mqtt/config/

root@debian:/opt/mqtt/config# vi mosquitto.conf

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
#password_file /mosquitto/data/passwd
allow_anonymous false
bind_address 0.0.0.0
socket_domain ipv4

기본적인 경로 설정과, 인증파일 경로, 그리고 익명 비허용 및 외부 연결을 위해 bind_address 를 0.0.0.0으로 설정합니다.

설정을 완료하고 컨테이너를 재시작합니다.

docker restart mqtt_wan

이 이후 mqtt 서버가 정상 동작을 할 것입니다. 이때 패스워드 파일을 컨테이너 내부로 들어가서 직접 생성해줍니다.

/ # mosquitto_passwd -c /mosquitto/data/passwd djjproject

계정 생성을 하고 나와서 mqtt 설정에서 password_file 부분의 커멘트를 풀고 재시작합니다.

root@debian:/opt/mqtt/config# vi mosquitto.conf

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
password_file /mosquitto/data/passwd
allow_anonymous false
bind_address 0.0.0.0
socket_domain ipv4

 

3. 설정 방법 - 2) 기존 mqtt 와 연동

기존 MQTT와 연동하기 위해서 둘 중 하나의 서버에 설정파일을 추가하면 양방향 연동됩니다.

일단은 다수의 서버의 환경에서는 한 방향으로만 연동을 해야하며, 교차로 연동을 하게 되면 중복으로 메시지가 계속 발행되니 연동에 조심하셔야합니다.

 

그러나, 이번에는 브로커가 2개 뿐이고, 만약에 여러개가 되더라도, 마스터는 외부 MQTT 서버가 될 것이기 때문에 계층 구조를 가짐으로 연동에 어려움은 없습니다.

--> High Avability 같은 방식의 구현에는 리던던시가 생기지 않도록 연동해야합니다.

기본적으로 로컬 MQTT 에서 외부용 MQTT 로 브릿지합니다.

A위치의 MQTT 서버는 포트포워딩이 불가능함으로 외부용 MQTT 서버와 연동할 때에는 아래와 같이 해야합니다.

A위치의 서버가 외부용 MQTT 에 연결해야 정상 동작이 됩니다.

 

그럼 데이터가 모두 외부용 MQTT 에만 의존하게 되는데요. 설정에 따라 모든 메시지가 위 그림의 4개의 MQTT 서버와 모두 공유됩니다.

메시지가 너무 많을 경우에는 특정 TOPIC 만 걸러서 연동을 하는게 좋을 것 같습니다.

 

이번에는 로컬 MQTT 와 외부용 MQTT 를 연동할 것인데요. 로컬 MQTT 설정에서 아래와 같이 입력합니다.

root@debian:/opt/mqtt/config# cat /etc/mosquitto/mosquitto.conf
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

# External MQTT Broker
connection external-bridge
address localhost:11883
topic # both 0
remote_username djjproject
remote_password 1234567890

위의 설정은 그렇게 어렵지 않으나, topic 부분이 어렵습니다.

topic # { in | out | both } { qos } "{ local_prefix }" "{ remote_prefix }"
# : 모든 토픽에 대해 브릿지
in : 상대 브릿지에서 들어오는 것만 받음
out : 상대 브릿지로 보내는 것만 브릿지
both : in + out 설정
qos : mqtt 메시지 qos 설정
local_prefix : 로컬 메시지일 경우 topic 에 붙일 단어
remote_prefix: 리모트 메시지일 경우 topic 에 붙일 단어

대부분 모든 데이터를 공유하고 주고 받으려면 # both 0 로 설정하고

특정 topic 만 사용할 경우 아래와 같습니다.

zigbee2mqtt_a_site 로만 topic 만 주고 받을 경우, zigbee2mqtt_a_site/# both 0 이런식으로 작성이 됩니다.

 

이렇게 설정하면 외부용 MQTT 서버에 데이터를 보내면 내부용 MQTT 에서도 메시지를 수신할 수 있습니다.

 

4. 간단한 테스트

외부 서버에서 외부용 MQTT로 메시지를 보내보겠습니다.

mosquitto-clients 패키지를 설치하면 간단히 테스트를 할 수 있습니다.

apt install mosquitto-clients

이 패키지를 설치하면 mosquitto_pub / mosquitto_sub 명령어를 사용할 수 있습니다.

먼저 아래의 커맨드로 메시지를 보내고,

mosquitto_pub -h domain.com -p 11883 -u djjproject -P 1234567890 -t djjproject -m "test message"

받는 쪽에서는 domain.com:11883 이 아닌, localhost 의 mqtt 서버에서 메시지를 대기해 보겠습니다.

로컬호스트는 익명 로그인이 허용 됨으로 퍼블리쉬 처럼 명령을 많이 넣을 필요가 없습니다.

root@debian:~# mosquitto_sub -t djjproject
# 메시지 전송
root@djjproject:/DATA# mosquitto_pub -h domain.com -p 11883 -u djjproject -P 1234567890 -t djjproject -m "test message" -d
Client mosqpub/15213-djjproject sending CONNECT
Client mosqpub/15213-djjproject received CONNACK
Client mosqpub/15213-djjproject sending PUBLISH (d0, q0, r0, m1, 'djjproject', ... (12 bytes))
Client mosqpub/15213-djjproject sending DISCONNECT

# 메시지 수신
root@debian:~# mosquitto_sub -t djjproject -d
Client mosqsub|20510-debian sending CONNECT
Client mosqsub|20510-debian received CONNACK (0)
Client mosqsub|20510-debian sending SUBSCRIBE (Mid: 1, Topic: djjproject, QoS: 0)
Client mosqsub|20510-debian received SUBACK
Subscribed (mid: 1): 0
Client mosqsub|20510-debian received PUBLISH (d0, q0, r0, m0, 'djjproject', ... (12 bytes))
test message

 

5. 다른 위치에 있는 zigbee2mqtt 서버 연동

일단 4번 섹션까지 모두 정리가 완료 되었습니다. 내부 외부를 구분하여 사용을 할 수 있게 되었습니다.

 

그러면, 내부 외부 구분 말고는 어디에 쓸 수 있을까 하는데요. zigbee2mqtt 서버가 A위치에 B위치에 돌고 있고, B위치에만 HA가 설치되었다고 가정하면 이 방법을 아래와 같이 사용할 수 있을 것 같습니다.

 

B위치의 HA <-----> B위치의 MQTT 서버<----> B위치의 Zigbee2MQTT

| A위치의 MQTT 서버 <-----> A위치의 Zigbee2MQTT

 

그러면 이 상황에서는 물론 A 위치에서 HA를 추가 운영하여 HA 끼리 연동하는 방법을 사용해 볼 수도 있는데요. 그런데 쓸데없이 2가지를 돌리는 겪이라 A위치의 MQTT 서버와 B위치의 MQTT 서버를 브릿지 처리만 해주면 문제 없이 2곳 이상의 Zigbee2MQTT 장비를 한곳에 몰아 사용하실 수 있습니다.

 

아래는 B쪽의 Z2M 현황이고 localhost 로 HA가 연동되어 있습니다.

A쪽은 Z2M 만 설치되어 있습니다.

 

A쪽 장비를 B에 연동해야하는데요. 그럼 아래와 같이 해결이 가능합니다.

 

1. homeassistant 토픽

이 부분은 그대로 두어야 장비 디스커버리가 됩니다.

2. zigbee2mqtt 토픽

이름을 바꾸어도 됩니다. B쪽을 zigbee2mqtt_2

A쪽을 zigbee2mqtt_1 으로 토픽이름을 맞춥니다.

# A쪽 설정
root@debian:~# cat /opt/z2m/configuration.yaml
homeassistant: true
permit_join: false
mqtt:
  base_topic: zigbee2mqtt_1
  server: mqtt://localhost
  user: djjproject

# B쪽 설정
root@debian:~# cat /opt/z2m/configuration.yaml
homeassistant: true
permit_join: false
mqtt:
  base_topic: zigbee2mqtt_2
  server: mqtt://localhost

이렇게 하면 각기 z2m 을 사용하실 수 있습니다.

 

이때 연동은 상황에 따라 다르겠지만, A쪽에서 포트포워딩이 쉽지 않아서 B에서 MQTT 서버를 오픈하고 A가 연결하여 브릿지 되도록 설정합니다.

# External MQTT Broker
connection external-bridge
address domain.com:11883
topic # both 0
remote_username djjproject
remote_password 1234567890

한편으로는 여러개 z2m 서버가 있다면 메인에 모이는 곳에 포트를 열어두고 다수의 mqtt 서버와 계층적으로 구조를 맺는게 맞아보입니다.

 

아래는 B장소의 온도센서2개와, A장소 온도센서2개 그리고 스마트플러그 8개가 한곳에 연동된 모습입니다.

 

6. 마치며

간단하게 알아보았습니다. 추후 많은 곳에 활용이 가능할 것으로 예상되네요.

 

마치겠습니다.

반응형

댓글