Реалізація карти розташування IoT-пристроїв у мобільному додатку
Сто датчиків на карті. Половина — онлайн, третина — в офлайні вже три години, кілька — з розрядженою батарейкою. Користувачу потрібно за секунду зрозуміти, де проблема, та натиснути на конкретний датчик, щоб побачити останні показання. Це стандартна задача IoT-моніторингу — та вона вирішується без екзотики.
Відображення пристроїв на карті
Маркер IoT-пристрою несе статус: online, offline, warning, critical. Колірне кодування — зелений/сірий/жовтий/червоний. Іконка міняється при оновленні через WebSocket без перезагрузки карти.
На Android Google Maps SDK: оновлюємо BitmapDescriptor маркера через marker.setIcon(getStatusIcon(device.status)). Щоб не створювати новий Bitmap на кожне оновлення статусу — кешуємо іконки по чотирьом статусам у HashMap<Status, BitmapDescriptor> при старті.
На iOS MapKit: переназначаємо MKAnnotationView.image через mapView(_:viewFor:) при зміні даних. Для плавного переходу кольору — UIView.transition(with:duration:options:animations:) на смену іконки.
У Flutter через Google Maps Flutter plugin: Marker(icon: BitmapDescriptor.fromBytes(pngBytes)). Важливо: BitmapDescriptor.fromAssetImage викликається асинхронно, якщо викликати його при кожному оновленні маркера — будуть джанки. Створюємо все іконки заздалегідь у initState та кешуємо.
Кластеризація при великій кількості пристроїв
При 100+ пристроях в одному viewport кластеризація обов'язкова. Для Flutter: google_maps_cluster_manager package. Для Android нативно: com.google.maps.android:android-maps-utils з DefaultClusterRenderer. Для iOS: GMUClusterManager з Maps Utils SDK.
Кастомний рендер кластера: показуємо не просто число, а статус «гіршого» пристрою в кластері — якщо хоч один critical, кластер червоний. Це дозволяє диспетчеру миттєво побачити проблемні зони без розкриття кожного кластера.
Детальний екран пристрою
Натискання на маркер — bottom sheet або navigation push з останніми даними пристрою: координата, час останнього пакету, показання датчиків, заряд батареї, рівень сигналу. Дані запитуються в момент відкриття через REST API /devices/{id}/latest, кешуються локально на 30 секунд.
Історія розташування: якщо пристрій мобільний (трекер, лічильник на транспорті) — трек за останні N годин. Якщо стаціонарний (датчик на будівлі) — тільки поточна позиція та факт онлайна.
Оновлення у реальному часі
WebSocket-підписка на оновлення флоту. Важливо не перерисовувати всю карту при кожному повідомленні — оновлюємо тільки змінені маркери. Diff-підхід: порівнюємо device.updatedAt та оновлюємо тільки ті об'єкти, де timestamp змінився.
При закритті додатку WebSocket закривається. При повернені — пересоздається. Обробка reconnect: експоненціальна затримка (1 сек → 2 → 4 → 8 → max 30 сек).
Пошук та фільтрація пристроїв
Список пристроїв рядом з картою — фільтрація по статусу, типу, групі. На Flutter — ListView.builder з локальною фільтрацією по List<Device>, без додаткових запитів до сервера. Пошук по імені пристрою — TextEditingController з debounce 300 мс.
На Android — RecyclerView з DiffUtil.Callback для оптимального diff при оновленні. Швидкий скролл по 200+ пристроям без лагів за рахунок view recycling та @Stable-анотацій на моделях (Compose).
Сортування: по статусу (критичні вгорі), по відстані від користувача, по імені. Сортування по відстані потребує поточну геолокацію користувача — запитуємо один раз при відкритті екрана, не оновлюємо постійно.
Графік
Карта пристроїв з кластеризацією, кольоровими статусами, детальним екраном та списком з фільтрацією при готовому API: 4 години — 2 робочих дні залежно від кастомізації маркерів та вимог до UI. Вартість розраховується після уточнення вимог.







