In the long run we want to track every Thing (real physical object) acting in a scenario.
Since every message implies the devices uniqueId, one Message Broker could operate as one single Tracker for a complete scenario. So all simulated devices could send their messages off the same Tracker and could be scaled and sudivided with a Message Broker like RabbitMQ, ActiveMQ etc.
We want to provide an independantly working GPS Tracker (simulation) for each of these things. A single device can be scaled with SEDA to decompose messages for event driven components.

Note

This implementation might help you to choose a Tracker Device Type for your real time scenario. The chosen protocol is a easy as it gets and the creation process can serve as a guideline.

The Model

We have chosen the OsmAnd protocol and defined the OsmAnd GPS Message (targeting Traccar). That is the information and format the server accepts and understands. We will use it as our Model to guide Tracker development. The protocol defines all attributes exchanged with the GTS platform.

We could generate a Java Class from the JSON format listed on the traccar osmand page.
But we want to go our own way and only use GPS platonic values for an initial GPS Tracker. We are primarily interested to transmit place & time and will fix the parameters in a simple record to hold a single GPS snapshot:

package bm.gps;

    public record MessageOsmand(
        // must have
        String id,        // traccar device uniqueId
        double lat,
        double lon,
        long timestamp,
        // optional objects to allow null values
        Double speed,
        Double bearing,
        Double altitude,
        Double battery,
        Double hdop) { }

A record is an immutable data class and much easier to handle than a POJO.

Record classes, which are a special kind of class, help to model plain data aggregates
with less ceremony than normal classes.
— https://docs.oracle.com/en/java/javase/17/language/records.html
Record Classes

Note that the primitive values are used as the "must haves" for GPS Tracking. At a later stage they can be abstracted to a GPS info interface to introduce different trackers to the same scenario.

The other values are modelled as objects in order to make them optional. Currently the traccar osmand page offers 16 different values, which can be introduced while we are prototyping.

  • For example the hdop, i.e. Horizontal dilution of precision is not relevant for us.
    It describes the quality of a message and we are only interested in the result.

  • On the other hand the accuracy can be missused to create a circle on the map,
    which might be interesting for certain scenarios.

No need for final decisions at this point.
Traccar also allows custom attributes, which could be sneeked into a scenario, if needed.

model deviations

The above model is a minimal starting example. A GPS Tracking Platform has to deal with a lot more attributes.
We will use the Traccar GTS, which is build on the following related Entities:

Attribute

Calendar

Command

CommandType

Device

DeviceAccumulators

Driver

Event

Geofence

Group

Maintenance

Notification

NotificationType

Permission

Position

ReportStops

ReportSummary

ReportTrips

Server

Statistics

User

These are not the actual Entities of the Traccar ERM.
These are DTO classes generated from the Traccar REST API openapi.yml file.

You can find the classes in the bm.traccar.generated.model.dto package
and they are available in every traccar-client- implementation.

Let’s compare the Device class and a json devices message sent via websocket:

      class Device {             {devices=[
        id: 638                     {id=638,
        name: runner                 name=runner,
        uniqueId: 10                 uniqueId=10,
        status: offline              status=online,
        disabled: false              disabled=false,
        lastUpdate: null             lastUpdate=2026-02-20T16:15:30.791+00:00,
        positionId: 0                positionId=0,
        groupId: 0                   groupId=0,
        phone: null                  phone=null,
        model: ro                    model=ro,
        contact: null                contact=null,
        category: null               category=null,
        attributes: {}               attributes={},
                                     calendarId=0,
                                     expirationTime=null
                                    }
                                 ]}

Both messages have the devices uniqueId in common to refer to the same device.
Yet the two models deviate by the two attributes calendar and expirationTime.
Important information for ETL stuff like mapping.

The other attributes of our Tracker Model record can be found in the Position class:

package bm.gps;                      bm.traccar.generated.model.dto;

    public record MessageOsmand (        public class Position {
        String id,                           deviceId : Long
        double lat,                          latitude : BigDecimal
        double lon,                         longitude : BigDecimal
        long timestamp,                       fixTime : OffsetDateTime
        Double speed,                           speed : BigDecimal
        Double bearing,                        course : BigDecimal
        Double altitude,                     altitude : BigDecimal
        Double battery,
        Double hdop) { }

geo precision

Another thing worth mentioning is the value- and type safety of decimals.
The openapi generator creates the Position class with BigDecimal types

private BigDecimal latitude, longitude, altitude;

The difference between BigDecimal and double is precision against performance.
For financial computation the precision, i.e. the exact sequence of numbers after the point, is indisputable.
With double the decimal values are not always precise.
For example, there is no precise decimal representation of one Third.
Therefor some tricky algorithm with memory has to make sure 1 / 3 * 3 is exactly 1.

This should be kept in the back of our mind, since it does matter when you want to know, if two points on a map are identical. Or you want to find all identical points in the complete map data. If the values are transfered with a string format like json or as URL parameters they are actually converted into their literal value.

To stay on the save side comparisons should always be made with tolerance.
For the Tracker and the Message we will use double, standard for most geotools and -libs.

Requirements

First we collect the functional requirements for the core features of tracking,
a Minimum Viable Product we can build on.
We have looked at the main Tracker Components earlier to gather requirements for the implementation:

GPS Unit / receiver

  • ✓ Acquire GPS position (latitude, longitude, altitude)

  • ✓ UTC Time

  • ❏ incoming Message Buffer here ?

(GSM) transmitter

  • ✓ Transmit messages (primarily location data) to a remote server (any TCP, UDP protocols)

  • ❏ configurable intervals e.g. every x seconds when moving, every y minutes when stationary etc.

  • ✓ manage connection to server, reconnection

  • ✓ outgoing Message Buffer

Controller

The main controller resides between receiving input and transmitting output. Most features of a Tracker can be implemented in it and it is the place to collect system information continuously.

  • ❏ Store last known position (or short history)

  • ❏ Fallback: store positions locally when no network → send burst when reconnected

  • ❏ Motion detection → change reporting frequency when moving vs. stationary

  • ❏ Determine basic movement data: speed, course/heading

  • ❏ provide basic status events: power on, transmitting, low battery, error.

  • ❏ Low-battery warning (send alert or change behavior)

  • ❏ Geofencing support (enter/exit alerts when crossing virtual boundaries)

This list can provide a guideline for software @Components and is sufficient to create a concrete implementation without surprises.

Message Buffer

  • ❏ longterm nice2have: analyze incoming data in millisecond intervals for real time events

Primary Use Case

the (Java) application developer,
i.e. user of the gps-osmand-tracker-1.1.1x.jar
wants to create a message and send it.
fire & forget