Реалізація моніторингу HVAC-систем через мобільний додаток
HVAC-контролери (Danfoss, Honeywell, Daikin VRV) рідко говорять на одному протоколі. Один об'єкт — Modbus RTU на RS-485 до приточних установок, BACnet/IP до чиллерів, патентований протокол до фанкойлів Daikin. Мобільний додаток працює з нормалізованими даними через API-шлюз, але розробнику потрібно розуміти звідки беруться числа, щоб правильно їх інтерпретувати та відображати.
Ключові параметри та їх джерела
Мінімальний набір для моніторингу клімату:
| Параметр | Джерело | Одиниця | Частота |
|---|---|---|---|
| Температура подачі/обертки | Датчики PT1000/NTC на трубопроводі | °C | 30 сек |
| Температура повітря в зоні | Кімнатний датчик або термостат | °C | 1 хв |
| Вологість | SHT31 або HIH6130 у зоні | %RH | 1 хв |
| Уставка (setpoint) | Контролер | °C | по змін |
| Стан компресора | Дискретний вхід контролера | on/off | по змін |
| COP (коефіцієнт ефективності) | Вичисляємий на backend | — | 5 хв |
Важливий нюанс: температура у Modbus Holding Registers часто приходить як знакове int16 у одиницях 0.1°C. Якщо контролер відправляє 0xFF9C, це не 65436°C — це -100, тобто -10.0°C. Неправильна інтерпретація — джерело класичної помилки «датчик показує -3200°C».
fun parseModbusTemperature(rawValue: Int): Double {
// Конвертуємо unsigned 16-bit у signed
val signed = if (rawValue > 32767) rawValue - 65536 else rawValue
return signed / 10.0
}
Реалізація на Android: polling через Retrofit + coroutines
Шлюз (Node-RED або самописний Go-сервіс) надає REST API. Polling з адаптивним інтервалом — агресивний коли додаток на передньому плані, рідкий у фоні:
class HvacPollingService(
private val api: HvacApi,
private val repository: HvacRepository,
) {
private var pollingJob: Job? = null
fun startPolling(scope: CoroutineScope, foreground: Boolean) {
pollingJob?.cancel()
val interval = if (foreground) 15_000L else 60_000L
pollingJob = scope.launch {
while (isActive) {
try {
val data = api.getHvacStatus()
repository.update(data)
} catch (e: IOException) {
// Логуємо, не крашимо — втрата зв'язку з шлюзом штатна ситуація
}
delay(interval)
}
}
}
}
Для об'єктів з MQTT-шлюзом використовуйте org.eclipse.paho.client.mqttv3. Топіки за зонами: hvac/{buildingId}/{unitId}/temperature, hvac/{buildingId}/{unitId}/setpoint.
Тренди та історія
Графік температури за тиждень — обов'язковий елемент. Дані за довгий період запитуємо з агрегацією на сервері (avg/min/max за годинними інтервалами), не тягнемо сирі 30-секундні записи. Рендеримо через MPAndroidChart (Android) або fl_chart (Flutter):
LineChartData buildTemperatureChart(List<TemperatureReading> history) {
return LineChartData(
lineBarsData: [
LineChartBarData(
spots: history.asMap().entries.map((e) =>
FlSpot(e.key.toDouble(), e.value.temperature)).toList(),
isCurved: true,
color: Colors.blue,
dotData: FlDotData(show: false),
),
],
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (value, meta) =>
Text(formatHour(history[value.toInt()].timestamp)),
),
),
),
);
}
Алерти по виходу з діапазону
Температура вийшла за межі — потрібно сповіщення. На сервері налаштовуємо правила (наприклад, через Node-RED або TimescaleDB continuous aggregates), push приходить через FCM. У додатку зберігаємо історію алертів локально у Room/SQLite — користувач повинен видіти коли та що сталось, навіть якщо смахнув сповіщення.
Розробка додатка моніторингу HVAC з real-time даними, історичними трендами та алертами: 4–6 тижнів. Вартість розраховується індивідуально після аналізу протоколів контролерів та кількості точок моніторингу.







