Реалізація моніторингу промислового обладнання через мобільний додаток
Моніторинг промислового обладнання — завдання не стільки розробки, скільки правильного вибору архітектури збору даних. Вібродатчик на підшипнику генерує 25 600 семплів в секунду. Температурний датчик — раз в 5 секунд. Струм двигуна — 1000 вимірів в секунду. Мобільний додаток не може та не повинен працювати з цим потоком напряму — тільки з агрегованими показниками, трендами та алертами.
Архітектура збору даних
На рівні обладнання дані збирає Edge-компонент: промислений шлюз (Moxa, Advantech, Siemens IPC) або кастомний Linux-сервер. Він нормалізує дані з різних протоколів та публікує агрегати в MQTT або отримує через REST/WebSocket.
Для мобільного додатка важливі два потоки:
- Реальний час — поточні значення ключових параметрів, оновлення раз в 1-5 секунд. WebSocket.
- Історія — тренди за смену, суть, тиждень. REST API з пагінацією та агрегацією.
Датчики → PLC / Edge Gateway → Time-Series DB (InfluxDB / TimescaleDB)
↓
Backend API (REST + WebSocket)
↓
Мобільний додаток
Реальний час через WebSocket: Flutter
class EquipmentMonitorRepository {
WebSocketChannel? _channel;
final StreamController<EquipmentState> _stateController =
StreamController.broadcast();
Stream<EquipmentState> get stateStream => _stateController.stream;
void connect(String equipmentId, String token) {
_channel = WebSocketChannel.connect(
Uri.parse('wss://iiot.factory.com/ws/equipment/$equipmentId'),
);
_channel!.stream
.map((event) => json.decode(event as String))
.map(EquipmentState.fromJson)
.listen(
_stateController.add,
onError: _handleError,
onDone: _scheduleReconnect,
);
_channel!.sink.add(json.encode({'auth': token}));
}
void _scheduleReconnect() {
Future.delayed(const Duration(seconds: 5), () => connect(_lastId, _lastToken));
}
}
BLoC для управління станом екрана моніторингу:
class EquipmentMonitorBloc extends Bloc<EquipmentEvent, EquipmentMonitorState> {
StreamSubscription<EquipmentState>? _subscription;
EquipmentMonitorBloc(this._repository) : super(EquipmentMonitorInitial()) {
on<StartMonitoring>((event, emit) async {
_subscription = _repository.stateStream.listen(
(state) => add(StateUpdated(state)),
);
_repository.connect(event.equipmentId, event.token);
});
on<StateUpdated>((event, emit) {
final current = event.state;
final isAlert = current.temperature > 85.0 || current.vibrationRms > 12.5;
emit(EquipmentMonitorRunning(state: current, hasAlert: isAlert));
});
}
}
Візуалізація трендів
Для історичних даних використовуємо fl_chart (Flutter) або MPAndroidChart (Android native). Ключова оптимізація — не передавати в чарт всі 86 400 точок за суть, а агрегувати на стороні API. Запит до InfluxDB-based API:
GET /api/v1/equipment/{id}/trend?
parameter=temperature&
from=2024-01-15T06:00:00Z&
to=2024-01-15T18:00:00Z&
resolution=300 # агрегація по 5 хвилин
Відповідь — 144 точки замість 43 200. Чарт малюється без фризів.
Baseline та відхилення
Корисна функція — відображення baseline (нормального діапазону) на графіку. Якщо струм двигуна в нормі 12-15А, виділяємо зону, та оператор одразу бачит відхилення:
LineChartData buildTrendChart(List<TrendPoint> data, Range baseline) {
return LineChartData(
extraLinesData: ExtraLinesData(
horizontalLines: [
HorizontalLine(y: baseline.min, color: Colors.green.withOpacity(0.3)),
HorizontalLine(y: baseline.max, color: Colors.green.withOpacity(0.3)),
],
),
betweenBarsData: [
BetweenBarsData(
fromIndex: 0,
toIndex: 0,
color: Colors.green.withOpacity(0.1),
),
],
lineBarsData: [
LineChartBarData(
spots: data.map((p) => FlSpot(p.timestamp.toDouble(), p.value)).toList(),
color: data.any((p) => p.value > baseline.max || p.value < baseline.min)
? Colors.red
: Colors.blue,
),
],
);
}
Алерти та еськалація
Простий алерт — push через FCM/APNs. Але для критичних ситуацій потрібна еськалація: якщо оператор не підтвердив алерт за 5 хвилин — сповіщення йде мастеру смини, потім начальнику цеху.
Логіку еськалації тримаємо на бекенді, мобільний додаток тільки відображає та підтверджує. Підтвердження алерта:
Future<void> acknowledgeAlert(String alertId) async {
await _dio.post('/api/v1/alerts/$alertId/acknowledge', data: {
'acknowledgedBy': currentUser.id,
'acknowledgedAt': DateTime.now().toIso8601String(),
'note': _noteController.text,
});
}
Екран алерта показує історію еськалації — хто отримав, хто бачив, хто підтвердив. Це важливо для постсменного аналізу.
Офлайн та робота в цеху
Виробничі цехи — зона нестабільного Wi-Fi. Критичні дані (поточні показники, активні алерти) кешуємо в SQLite через Room або Drift. При втраті з'єднання показуємо останнє відоме стан з міткою «дані від HH:MM, немає зв'язку».
Розробка додатка моніторингу для одного типу обладнання з WebSocket телеметрією та історичними трендами — 4-6 тижнів. Додавання підтримки кількох типів обладнання, складних алертів з еськалацією, офлайн-режиму — 2-3 місяці. Вартість розраховується індивідуально після аналізу источників даних та вимог до надійності.







