๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๐ŸŒฎ ๐Ÿ’ฌ
๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป/mqtt

[MQTT] presence detection ์—์„œ qos ์™€ retain ์„ค์ •

by ๋ฐ”์ฟ„๋ฆฌ 2025. 5. 8.

 

์ตœ๊ทผ ์ง„ํ–‰ํ•œ ๊ฒƒ ์ค‘์— ์œ ์šฉํ•˜๊ฒŒ ์ž˜ ์‚ฌ์šฉํ•œ paho-mqtt option์ด ์žˆ์–ด์„œ ๊ธฐ๋กํ•œ๋‹ค.

 

์•„๋ž˜์™€ ๊ฐ™์€ mqtt ๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ์—ˆ๋‹ค

mqtt ํ†ต์‹ ์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด์„œ main client ์—์„œ sub client ์˜ ์—ฐ๊ฒฐ ์ƒํƒœ(online/offline)๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ qos, retain์„ ์„ค์ •ํ•˜๊ณ , will_set๋„ ๋“ฑ๋กํ–ˆ๋‹ค

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉฐ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž!

 

โœจ ์—ฌ๊ธฐ์„œ ์ƒˆ๋กœ ์•Œ๊ฒŒ๋œ ์šฉ์–ด : presence detection

→ IoT, MQTT, ์ฑ„ํŒ… ์‹œ์Šคํ…œ์— ๋งŽ์ด ์“ฐ์ด๋Š” ๊ฐœ๋…์ด๋‹ค.

→ ํ˜„์žฌ ๋ˆ„๊ฐ€ ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€(online), ๋ˆ„๊ฐ€ ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ๋Š”์ง€(offline)์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ์‹œ์Šคํ…œ์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ํŒŒ์•…ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

→ "ํด๋ผ์ด์–ธํŠธ์˜ ์ ‘์† ์ƒํƒœ ๊ฐ์ง€" ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋  ๋“ฏ !

 

 

 

์šฐ์„ , sub client์—์„œ๋Š” {"client1": "online"} ์ด๋Ÿฐ ํ˜•์‹์œผ๋กœ publish ํ•  ์˜ˆ์ • !!

 

Main Client ์ธก ์Šคํฌ๋ฆฝํŠธ์—๋Š” ์ด๋ ‡๊ฒŒ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

self.status_map = {}

def on_connect(self, client, userdata, flags, rc):
    ...
    self.subscribe("status/#")
    logger.info("[MQTT] Subscribe 'agents/status'!")
    ...

def on_message(self, client, userdata, msg):
    ...
    if msg.topic.startswith('status'):
        self._handle_status_update(message)
    ...
  
def _handle_status_update(self, message):
    agent = message.get("agent")
    status = message.get("status")
    if agent and status:
        self.status_map[agent] = status
        logger.info(f"[STATUS] {agent} → {status}")
    logger.info(f'[STATUS_MAP] status_map: {self.status_map}')

def get_agent_status(self, agent):
    return self.status_map.get(agent, "unknown")

def is_agent_online(self, agent):
    return self.get_agent_status(agent) == "online"

 

(1) status_map : ์—ฐ๊ฒฐ๋œ agents ์ƒํƒœ๋ฅผ ๋‹ด์„ dictionary

 

(2) on_connect()

- mqtt ์—ฐ๊ฒฐ ์™„๋ฃŒ ํ›„ "status/#" ๊ตฌ๋… ์‹œ์ž‘

- "status/#" : "status/" ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  topic์„ ๊ตฌ๋…

 

(3) on_message()

- message๋ฅผ ๋ฐ›์œผ๋ฉด _handle_status_update ์‹คํ–‰

 

(4) _handle_status_update()

- status_map์ด๋ผ๋Š” dict์— {“agent1”: “online”, “agent2”: “offline”} ํ˜•์‹์œผ๋กœ ์ƒํƒœ๋ฅผ ์ €์žฅ

 

(5) is_agent_online()

- ๋‚˜์ค‘์— agent ์—ฐ๊ฒฐ ํ™•์ธํ•  ๋•Œ ์‚ฌ์šฉํ•  ํ•จ์ˆ˜

 

sub client ์ธก์—๋Š” online/offline ์„ publish ํ•˜๋„๋ก ์ถ”๊ฐ€ํ–ˆ๋‹ค.

1๏ธโƒฃ connect ๋˜๋ฉด online ์ „์†ก

def on_connect(self, client, userdata, flags, rc):
    ...
    online_message = {self.client_id: "online"}
    self.client.publish("agents/status", json.dumps(online_message), qos=1, retain=True)

 

2๏ธโƒฃ ์ •์ƒ์ ์ธ disconnect ์—์„œ offline ์ „์†ก

def on_disconnect(self, client, userdata, flags, rc):
    offline_message = {self.client_id: "offline"}
    self.client.publish("agents/status", json.dumps(offline_message), qos=1, retain=True)

 

3๏ธโƒฃ ๋น„์ •์ƒ์ ์ธ disconnect ์—์„œ offline ์ „์†ก

client.connect(broker_host, broker_port)
will_message = {client_id: "offline"}
client.will_set("agents/status", payload=json.dumps(will_message), qos=1, retain=True)

* will_set : client๊ฐ€ ๋น„์ •์ƒ์ ์œผ๋กœ disconnect ๋˜์—ˆ์„ ๋•Œ broker๊ฐ€ ๋Œ€์‹  publishํ•˜๋Š” message

 

โญ๏ธ qos=1, retain=True

  • ์„ค์ •์„ ์ถ”๊ฐ€ํ•œ ์ด์œ 
    • sub client๊ฐ€ ๋จผ์ € mqtt ์—ฐ๊ฒฐ๋˜๊ณ  ๋‚˜์„œ Main Client๊ฐ€ "status/#" ๊ตฌ๋…์„ ํ•˜๊ฒŒ๋˜๋ฉด, sub client๋“ค์˜ ์ƒํƒœ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์—†๋‹ค.
  • retain=True
    • broker์— ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅ(retain) ํ•˜๋ผ๊ณ  ์•Œ๋ ค์ฃผ๋Š” flag
    • ์ƒˆ๋กœ์šด subscriber๊ฐ€ ๊ตฌ๋…ํ•˜๋ฉด broker๋Š” ์ €์žฅ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฆ‰์‹œ ์ „๋‹ฌํ•œ๋‹ค.
  • qos=1
    • ๋ฉ”์‹œ์ง€๊ฐ€ ์ตœ์†Œ 1ํšŒ ์ด์ƒ ์ „๋‹ฌ๋จ (at least once)
    • publish → broker → subscriber ๊ฐ„ ACK(ํ™•์ธ ์‘๋‹ต) ์„ ์ฃผ๊ณ ๋ฐ›์Œ
  • ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณผ์ • (publish → broker)์— ์‹คํŒจํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด qos=1 ์ด์ƒ ์“ฐ๋Š”๊ฒŒ ์œ ๋ฆฌ.
  • ๋„คํŠธ์›Œํฌ๊ฐ€ ์•ˆ์ •์ ์ด๋ฉด qos=0 ์œผ๋กœ ํ•ด๋„ ๊ดœ์ฐฎ์œผ๋‚˜, presence detection(ํด๋ผ์ด์–ธํŠธ์˜ ์ ‘์† ์ƒํƒœ ๊ฐ์ง€, online/offline) ์—์„œ๋Š” ์‹ค์‹œ๊ฐ„์„ฑ์ด ์ค‘์š”ํ•˜๊ณ  ์ตœ์‹  ์ •๋ณด๊ฐ€ broker์— ์ž˜ ์ €์žฅ๋˜์–ด์•ผ ํ•˜๋‹ˆ๊นŒ qos=1 ์œผ๋กœ ์„ค์ •
  • qos=2๋Š” ๋„ˆ๋ฌด ๋ฌด๊ฒ๋‹ค