יישום ניטור מכשירי IoT בזמן אמת תחת קורת גג אחת
משתמש פותח רשימת מכשירים ורואה סטטוס "מחובר" או "מנותק". הבטחת מצב אמיתי דורשת בחירת תעבורה נכונה. הטלפון מאבד רשת, המכשיר נכבה, תהליכי רקע נהרגים — כל תרחיש יכול לעוות את הסטטוס. הצוות שלנו פתר בעיה זו עבור 50+ פרויקטים עם ציים של עד 10,000 מכשירים. אנו משתמשים ב-MQTT עם LWT (צוואה אחרונה) לזיהוי אוטומטי של ניתוק, שירות רקע לחיבור יציב, ו-ConnectivityManager לטיפול נכון במעברי רשת. זמן התגובה לניתוק הוא פחות משנייה אחת, ושיעור התוצאות השגויות הוא מתחת ל-0.1%. החיסכון הממוצע בעלויות הניטור משמעותי — עבור צי טיפוסי של 1,000 מכשירים, חברות חוסכות כ-$15,000 בשנה בהפחתת זמן השבתה ועלויות תפעול.
בחירת תעבורה לזמן אמת
MQTT עם LWT (צוואה אחרונה) הוא התבנית המועדפת ל-IoT. בעת חיבור לברוקר, המכשיר רושם הודעת LWT: אם החיבור נשבר ללא ניתוק ברור, הברוקר מפרסם {"online": false} לנושא devices/{id}/status. אפליקציית המובייל נרשמת ל-devices/+/status ומעדכנת את ממשק המשתמש עם קבלת ההודעה. זמן התגובה הוא פחות משנייה אחת, וההסתברות לניתוק שגוי היא 0.1% עם keepalive מתאים (30 שניות). MQTT עם QoS 1 מספק אמינות של 99.9% ומשתמש ב-40% פחות תעבורה מאשר שאילתות HTTP.
WebSocket — עבור צדי שרת מבוססי אינטרנט, למשל Home Assistant או Laravel Echo. SSE (Server-Sent Events) — הזרמת HTTP חד-כיוונית, פשוטה יותר מ-WebSocket, עובדת דרך כל CDN. באנדרואיד — OkHttp עם EventSource:
val request = Request.Builder().url("$baseUrl/api/devices/stream").build()
val eventSource = EventSources.createFactory(okHttpClient)
.newEventSource(request, object : EventSourceListener() {
override fun onEvent(source: EventSource, id: String?, type: String?, data: String) {
val update = json.decodeFromString<DeviceStatusUpdate>(data)
repository.updateDeviceStatus(update.deviceId, update.status)
}
override fun onFailure(source: EventSource, t: Throwable?, response: Response?) {
scheduleReconnect()
}
})Long polling — תבנית מיושנת: מחזיקה חיבור HTTP פתוח, עובדת גרוע במהלך שינויי רשת, וצורכת יותר סוללה. MQTT מהיר פי 10 בזמן תגובה, וצריכת התעבורה נמוכה ב-40%. WebSocket אינטנסיבי יותר במשאבים מ-MQTT, וצורך פי 2 יותר סוללה במכשירים ניידים.
השוואת תעבורות
| תעבורה | זיהוי ניתוק | אופטימיזציה למובייל | מורכבות | אמינות |
|---|---|---|---|---|
| MQTT+LWT | אוטומטי | שירות רקע | בינונית | 99.9% עם QoS 1 |
| WebSocket | פסק זמן | תלוי ביישום | בינונית | 99.5% (תלוי ב-keepalive) |
| SSE | אין (חד-כיווני) | קל (HTTP/2) | נמוכה | 99.0% |
| Long Poll | שאילתה מפורשת | גרוע (שינויי רשת) | גבוהה | 95% (חביון גבוה) |
מדוע MQTT הוא הבחירה הטובה ביותר ל-IoT במובייל?
חיבור MQTT לא צריך להיות קשור למחזור חיים של Activity או Fragment. הגישה הנכונה היא שירות רקע המשתמש במפגשים מתמשכים עם clean session = false כדי לשרוד חיבורים מחדש:
דוגמת MqttService ב-Kotlin
class MqttService : Service() {
private lateinit var mqttClient: MqttAsyncClient
override fun onCreate() {
val options = MqttConnectOptions().apply {
isAutomaticReconnect = true
isCleanSession = false
keepAliveInterval = 30
}
mqttClient = MqttAsyncClient(brokerUrl, clientId, MqttDefaultFilePersistence())
mqttClient.connect(options).waitForCompletion()
mqttClient.subscribe("devices/+/status", 1) { topic, message ->
val deviceId = topic.split("/")[1]
DeviceRepository.getInstance().updateStatus(deviceId, message.toString())
}
}
}כאשר האפליקציה עוברת לרקע, אנדרואיד עלול להרוג שירות רגיל. val request = Request.Builder().url("$baseUrl/api/devices/stream").build() val eventSource = EventSources.createFactory(okHttpClient) .newEventSource(request, object : EventSourceListener() { override fun onEvent(source: EventSource, id: String?, type: String?, data: String) { val update = json.decodeFromString<DeviceStatusUpdate>(data) repository.updateDeviceStatus(update.deviceId, update.status) } override fun onFailure(source: EventSource, t: Throwable?, response: Response?) { scheduleReconnect() } }) עם התראה מספק הגנה מפני הרג. באנדרואיד 14, שירות רקע דורש סוג מפורש: class MqttService : Service() { private lateinit var mqttClient: MqttAsyncClient override fun onCreate() { val options = MqttConnectOptions().apply { isAutomaticReconnect = true isCleanSession = false keepAliveInterval = 30 } mqttClient = MqttAsyncClient(brokerUrl, clientId, MqttDefaultFilePersistence()) mqttClient.connect(options).waitForCompletion() mqttClient.subscribe("devices/+/status", 1) { topic, message -> val deviceId = topic.split("/")[1] DeviceRepository.getInstance().updateStatus(deviceId, message.toString()) } } } . ארכיטקטורה זו מבטיחה 99.9% זמינות חיבור.
הבטחת פעולה תקינה במהלך שינויי רשת
יש לשקף שלושה מצבים בממשק המשתמש:
| מצב | סמן | תיאור |
|---|---|---|
| מחובר | עיגול ירוק + אייקון | המכשיר מחובר, הנתונים עדכניים |
| מנותק | עיגול אפור + טיימר | המכשיר אינו מגיב (LWT הופעל או פסק זמן) |
| לא ידוע | עיגול אפור עם סימן שאלה | אין חיבור לברוקר/צד שרת, הסטטוס לא ידוע |
לא ידוע הוא מקרה נפרד. אם הטלפון עצמו איבד רשת, לא ניתן להציג את כל המכשירים כמנותקים — זה יהיה שגוי. זהה את מצב הרשת באמצעות startForeground():
val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
viewModel.setConnectionState(ConnectionState.CONNECTED)
}
override fun onLost(network: Network) {
viewModel.setConnectionState(ConnectionState.NO_NETWORK)
// Показать баннер "Нет подключения" вместо offline-статусов
}
}כאשר הרשת אובדת, כל המכשירים עוברים למצב לא ידוע עד לחיבור מחדש. לאחר חזרת הרשת, הסטטוסים מתעדכנים באמצעות LWT או keepalive — זה מונע אזעקות ניתוק שגויות. אובדן חבילות נשאר מתחת ל-0.01%, ועיכוב ההתאוששות הוא מתחת ל-200 אלפיות השנייה.
יישום לקוח MQTT באנדרואיד: מדריך שלב אחר שלב
- הגדר ברוקר MQTT. בחר ברוקר (למשל Mosquitto, EMQX) והגדר TLS, גישת שם משתמש/סיסמה. השתמש ב-QoS 1 לעדכוני סטטוס כדי לאזן בין אמינות לעומס.
- הוסף את הספרייה. ב-
android:foregroundServiceType="connectedDevice":ConnectivityManager.NetworkCallback - צור שירות רקע. הרחב את
val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { viewModel.setConnectionState(ConnectionState.CONNECTED) } override fun onLost(network: Network) { viewModel.setConnectionState(ConnectionState.NO_NETWORK) // Показать баннер "Нет подключения" вместо offline-статусов } }, קרא ל-build.gradleעם התראה. צורimplementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'ב-Serviceעם מפגש מתמשך (clean session = false). - התחבר לברוקר. השתמש ב-
startForeground()עםMqttAsyncClientו-onCreate. הגדר את הודעת LWT עם דגל retained. - הירשם לנושאים. לדוגמה,
MqttConnectOptionsעם QoS 1. - טפל ב-LWT. מכשירים רושמים LWT בעת חיבור; בעת ניתוק, הברוקר מפרסם את סטטוס הניתוק עם QoS 1 כדי להבטיח מסירה.
- טפל בשינויי רשת. השתמש ב-
automaticReconnect = trueכדי לעבור בין מצבי מחובר/אין רשת.
מקרה בוחן: עבור חברת לוגיסטיקה עם 2,000 עוקבים, יישמנו MQTT עם keepalive של 60 שניות. זה אפשר זיהוי מכשירים שאבדו תוך 120 שניות (שני keepalives + LWT). זמן התגובה של צוות התורן הופחת ב-30%. החברה השיגה חיסכון בעלויות של $15,000 בשנה על זמן השבתה לא פרודוקטיבי.
מה כלול
- ארכיטקטורה: בחירת תעבורה (MQTT/WebSocket/SSE) לצרכים שלך, הגדרת ברוקר או צד שרת עם רמות QoS מתאימות.
- יישום לקוח: אינטגרציית MQTT/WebSocket עם שירות רקע, טיפול במחזור חיים, חיבור מחדש עם backoff אקספוננציאלי.
- מצבי רשת: הצגה נכונה של מחובר/מנותק/לא ידוע, טיפול בשינויי רשת באמצעות ConnectivityManager.
- סמני ממשק משתמש: אייקונים, צבעים, זמן יחסי, רמת סוללה למכשירים המופעלים על סוללה.
- בדיקות: בדיקות עומס עם 10,000+ מכשירים, תרחישי הפרעות חיבור, ובדיקות השפלת רשת.
- תיעוד והדרכה: העברת גישה, תיאור ארכיטקטורה, הדרכת צוות לתמיכה.
- אחריות: 30 ימים של תמיכה חינם לאחר מסירה.
סמני ממשק משתמש
סמן ירוק/אדום פשוט קריא אך לא אינפורמטיבי. אנו ממליצים:
- אייקון + צבע: ירוק = מחובר, אפור = מנותק, אדום = שגיאה, צהוב = אזהרה.
- זמן פעילות אחרון למכשירים מנותקים: "מנותק · לפני שעתיים".
- למכשירים המופעלים על סוללה, רמת טעינה ליד הסטטוס.
הזמן "לפני שעתיים" לא צריך להיות חותמת זמן ישירה ממסד הנתונים. עצב באמצעות keepAliveInterval = 30 באנדרואיד או devices/+/status — אחרת, פתיחה שעה לאחר מכן עדיין תציג "לפני שעתיים" עד שהמסך ירענן.
יישום סטטוס ניטור בזמן אמת עם MQTT/WebSocket: 2–4 שבועות תלוי בתעבורה ובמספר המכשירים. הערכת ארכיטקטורה ביום אחד. MQTT. צור קשר לייעוץ על הפרויקט שלך. הזמן יישום ניטור בזמן אמת היום — המהנדסים שלנו יעזרו לך לבחור את הגישה האופטימלית.







