Repository navigation
Expand file tree
/
Copy pathasync_example.py
More file actions
143 lines (125 loc) · 5.21 KB
/
Copy pathasync_example.py
File metadata and controls
143 lines (125 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import asyncio
import flowsdk
import time
from flowsdk import FlowMqttClient, TransportType, MqttOptionsFfi, MqttEngineFfi
async def main():
print("🚀 FlowSDK No-IO Async Example")
print("=" * 60)
# 1. Create the engine
import random
client_id = f"python_async_no_io_{random.randint(1000, 9999)}"
opts = MqttOptionsFfi(
client_id=client_id,
mqtt_version=5,
clean_start=True,
keep_alive=60,
username=None,
password=None,
reconnect_base_delay_ms=1000,
reconnect_max_delay_ms=30000,
max_reconnect_attempts=0,
)
engine = MqttEngineFfi.new_with_opts(opts)
print(f"✅ Created MqttEngineFfi (Client ID: {client_id})")
# 2. Establish TCP connection using asyncio
broker_host = "broker.emqx.io"
broker_port = 1883
print(f"📡 Connecting to {broker_host}:{broker_port}...")
try:
reader, writer = await asyncio.open_connection(broker_host, broker_port)
except Exception as e:
print(f"❌ Connection failed: {e}")
return
print("✅ TCP Connected")
# 3. Initiate MQTT connection
engine.connect()
# 4. Main orchestration loop
try:
# Run for 15 sconds
start_time = time.monotonic()
end_time = start_time + 15
# Subscribe/Publish state
subscribed = False
published = False
while time.monotonic() < end_time:
now_ms = engine.elapsed_ms()
# 1. Handle protocol timers
engine.handle_tick(now_ms)
# 2. Handle network input (non-blocking-ish)
try:
# Use a small timeout to keep the loop pumping
data = await asyncio.wait_for(reader.read(4096), timeout=0.05)
if data:
print(f"📥 Received {len(data)} bytes from network")
engine.handle_incoming(data)
elif reader.at_eof():
print("📥 Reader got EOF")
engine.handle_connection_lost()
break
except asyncio.TimeoutError:
# No data available in this tick, that's fine
pass
except Exception as e:
print(f"❌ Read error: {e}")
engine.handle_connection_lost()
break
# 3. Handle network output
outgoing = engine.take_outgoing()
if outgoing:
print(f"📤 Sending {len(outgoing)} bytes to network...")
writer.write(outgoing)
await writer.drain()
# 4. Process all accumulated events
events = engine.take_events()
for event in events:
if event.is_connected():
res = event[0]
print(f"✅ MQTT Connected! (Reason: {res.reason_code}, Session Present: {res.session_present})")
elif event.is_disconnected():
print(f"💔 MQTT Disconnected! (Reason: {event.reason_code})")
elif event.is_message_received():
msg = event[0]
print(f"📨 Message on '{msg.topic}': {msg.payload.decode()} (QoS: {msg.qos})")
elif event.is_subscribed():
res = event[0]
print(f"✅ Subscribed (PID: {res.packet_id}, Reasons: {res.reason_codes})")
elif event.is_published():
res = event[0]
print(f"✅ Published (PID: {res.packet_id}, Reason: {res.reason_code})")
elif event.is_error():
print(f"❌ Engine Error: {event[0].message}")
elif event.is_reconnect_needed():
print("🔄 Engine signaled ReconnectNeeded")
elif event.is_reconnect_scheduled():
print(f"⏰ Engine scheduled reconnect (Attempt {event.attempt}, Delay {event.delay_ms}ms)")
elif event.is_ping_response():
print(f"🏓 Ping Response (Success: {event.success})")
# 5. Application logic
if engine.is_connected():
if not subscribed:
pid = engine.subscribe("test/python/no_io", 1)
print(f"📑 API -> subscribe('test/python/no_io', qos=1) -> PID: {pid}")
subscribed = True
elif not published:
pid = engine.publish("test/python/no_io", b"Hello from Python No-IO!", 1, None)
print(f"📤 API -> publish('test/python/no_io', payload='...', qos=1) -> PID: {pid}")
published = True
except Exception as e:
print(f"❌ Loop error: {e}")
finally:
# 6. Disconnect gracefully
print("\n👋 Disconnecting...")
if not writer.is_closing():
engine.disconnect()
outgoing = engine.take_outgoing()
if outgoing:
writer.write(outgoing)
await writer.drain()
writer.close()
await writer.wait_closed()
print("✅ Done")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
pass