Разработка мобильного приложения для автомобильной телематики (Connected Car)
Connected Car — экосистема, где автомобиль говорит с облаком постоянно: позиция GPS, данные CAN-шины, состояние подсистем. Мобильное приложение — окно в эту экосистему для владельца или диспетчера автопарка. За простым интерфейсом «посмотреть где машина» скрывается многоуровневый стек: протоколы телематических блоков управления (ТБУ), серверная платформа, real-time API и сложная бизнес-логика трекинга, алертов и аналитики.
Телематический блок управления и протоколы
ТБУ (или AVL-трекер) — OBD-II или CAN-устройство с GSM/LTE модемом, GPS-модулем и внутренней памятью для буферизации. Популярные серии: Teltonika FMB (FMB920, FMB003, FMB125), Concox GT06N, Queclink GV500.
Данные с ТБУ уходят на сервер по TCP в проприетарном бинарном протоколе. Teltonika Codec 8/8E — наиболее распространённый:
Preamble (4 байта): 0x00000000
Data Field Length (4 байта)
Codec ID (1 байт): 0x08 (Codec8) или 0x8E (Codec8 Extended)
Number of Data (1 байт): количество AVL-записей
[AVL records]
Number of Data (1 байт): повтор для проверки
CRC-16 (4 байта)
Каждая AVL-запись: timestamp (8 байт Unix ms), GPS-данные (lat/lon/alt/angle/satellites/speed), IO Elements (батарея, зажигание, пробег, входы/выходы, CAN-данные).
Парсинг на сервере (Go):
type AVLRecord struct {
Timestamp time.Time
Longitude float64
Latitude float64
Altitude int16
Angle uint16
Satellites uint8
Speed uint16
IOElements map[uint16]int64
}
func parseAVLRecord(r *bufio.Reader) (AVLRecord, error) {
var rec AVLRecord
var tsMs uint64
binary.Read(r, binary.BigEndian, &tsMs)
rec.Timestamp = time.UnixMilli(int64(tsMs))
var priority uint8
binary.Read(r, binary.BigEndian, &priority)
// GPS Element: lon(4), lat(4), alt(2), angle(2), sat(1), speed(2)
var lonRaw, latRaw int32
binary.Read(r, binary.BigEndian, &lonRaw)
binary.Read(r, binary.BigEndian, &latRaw)
rec.Longitude = float64(lonRaw) / 10_000_000.0
rec.Latitude = float64(latRaw) / 10_000_000.0
// ... остальные поля
return rec, nil
}
Серверная платформа: Traccar или своя
Traccar — open-source platform, знает 200+ протоколов трекеров, предоставляет REST API и WebSocket. Оптимальный выбор для старта и средних автопарков.
Traccar REST API для мобильного клиента:
interface TraccarApi {
@GET("devices")
suspend fun getDevices(@Query("groupId") groupId: Long? = null): List<Device>
@GET("positions")
suspend fun getLatestPositions(
@Query("deviceId") deviceId: Long? = null
): List<Position>
@GET("reports/trips")
suspend fun getTrips(
@Query("deviceId") deviceId: Long,
@Query("from") from: String, // ISO 8601
@Query("to") to: String,
): List<Trip>
@GET("reports/events")
suspend fun getEvents(
@Query("deviceId") deviceId: Long,
@Query("from") from: String,
@Query("to") to: String,
@Query("type") types: List<String>,
): List<Event>
}
Real-time позиции — WebSocket Traccar (wss://server/api/socket):
class TraccarLiveSession(private val baseUrl: String, private val sessionCookie: String) {
fun observe(): Flow<TraccarMessage> = callbackFlow {
val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build()
val ws = client.newWebSocket(
Request.Builder()
.url("wss://$baseUrl/api/socket")
.header("Cookie", "JSESSIONID=$sessionCookie")
.build(),
object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
trySend(Json.decodeFromString(text))
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
close(t)
}
}
)
awaitClose { ws.close(1000, null) }
}
}
Карта автопарка с живыми маркерами
Google Maps SDK — стандарт для Android, MapKit для iOS, Mapbox или Yandex MapKit для российского рынка (Google Maps недоступен в отдельных регионах).
Маркеры транспортных средств с анимацией перемещения между позициями:
private fun updateVehicleMarker(position: Position) {
val latLng = LatLng(position.latitude, position.longitude)
val existing = vehicleMarkers[position.deviceId]
if (existing == null) {
vehicleMarkers[position.deviceId] = map.addMarker(
MarkerOptions()
.position(latLng)
.icon(getVehicleIcon(position.attributes["ignition"] as? Boolean ?: false))
.rotation(position.course.toFloat())
.flat(true) // маркер вращается вместе с картой
)!!
} else {
// Плавная анимация перемещения
ValueAnimator.ofFloat(0f, 1f).apply {
duration = 1000
interpolator = LinearInterpolator()
val from = existing.position
addUpdateListener { anim ->
val f = anim.animatedFraction
existing.position = LatLng(
from.latitude + (latLng.latitude - from.latitude) * f,
from.longitude + (latLng.longitude - from.longitude) * f
)
existing.rotation = position.course.toFloat()
}
}.start()
}
}
Кластеризация для автопарков с > 50 машин: ClusterManager из Maps SDK Utilities. Без кластеризации карта с сотнями маркеров лагает — на Android у GoogleMap внутреннее ограничение на количество маркеров без кластеризации.
История поездок и геозоны
Трек поездки — Polyline по списку GPS-точек. Ломаная линия цветная по скорости (зелёный/жёлтый/красный) даёт мгновенное визуальное понимание манеры езды:
fun drawSpeedColoredRoute(points: List<Position>) {
points.zipWithNext().forEach { (from, to) ->
val color = when {
to.speed > speedLimitKph -> Color.RED
to.speed > speedLimitKph * 0.8 -> Color.YELLOW
else -> Color.GREEN
}
map.addPolyline(
PolylineOptions()
.add(LatLng(from.latitude, from.longitude))
.add(LatLng(to.latitude, to.longitude))
.color(color)
.width(4f)
)
}
}
Геозоны — полигоны на карте, при пересечении которых сервер генерирует события. Создание геозоны из мобильного приложения: рисуем полигон тапами на карте, отправляем список координат в Traccar Geofences API. Привязка устройства к геозоне через notificationTypes (geofenceEnter, geofenceExit).
CAN-данные и расширенная телематика
Через OBD-II порт или прямое подключение к CAN-шине (ТБУ типа Teltonika FMB003 с CAN-адаптером) получаем: уровень топлива, пробег из ECU (точнее одометра), обороты двигателя, нагрузку, коды ошибок DTC, температуру охлаждающей жидкости.
Эти данные приходят в IOElements AVL-записи по заранее сконфигурированным IO ID. Для Teltonika: IO ID 12 = ignition, ID 67 = CAN speed, ID 82 = CAN fuel level. Маппинг IO ID → параметр хранится на сервере, мобильный клиент получает уже именованные поля.
Уведомления и алерты
Алерты настраиваются на сервере (Traccar Notifications → по типам событий) и доставляются через FCM или APNS. Типовые алерты автопарка:
- превышение скорости > X км/ч
- выезд из геозоны в нерабочее время
- длительная стоянка с включённым двигателем (расход вхолостую)
- разряд аккумулятора (< 11.8 В)
- резкое торможение / ускорение (из данных акселерометра ТБУ)
- потеря связи с устройством > 5 минут
На мобильном клиенте — лента алертов с фильтрацией по типу и устройству, переход к карте с позицией в момент события.
Отчёты
Отчёты по пробегу, поездкам, простоям, топливу — формируются на сервере (Traccar Reports API), в мобильном приложении отображаются и экспортируются в PDF/Excel. Генерация PDF через pdf пакет Flutter или через серверный endpoint.
Разработка мобильного приложения для автопарка с картой, real-time позициями, историей поездок и алертами на основе Traccar: 8–12 недель. Кастомная телематическая платформа с CAN-данными, расширенной аналитикой и белым лейблом: 4–6 месяцев. Стоимость рассчитывается индивидуально после анализа парка трекеров и бизнес-требований.







