How to handle spurious events from a device

jond2 years ago

I am testing a battery powered GPS device which misuses several aspects of its protocol. The documentation for the device in fact mentions this. In particular, the device sends events to the server which are spurious, such as High Temperature, Towed, Ignition On, etc when in truth the device is not capable of monitoring these things. According to the device's documentation, these spurious events are meant to distinguish the 7 different operating modes of the device, which include different reporting intervals, power optimizations, fallback modes, etc.

My goal is to prevent this junk data from being used by Traccar or at least hide it from users in the web platform. Is there a way to prevent Traccar from raising an Alarm from these fake events? I do not want to suppress all Alarms, because some events from the device are genuine, e.g. low battery voltage.

Another option I see is to rewrite the protocol decoder to ignore the spurious data, then rebuild Traccar. But I am reluctant to do this because it seems very hacky and there would be a possibility of breaking the live service. What would be the best way forward?

Anton Tananaev2 years ago

You can set up computed attributes that would remove those specific alarms.

jond2 years ago

Hi Anton, thanks for the advice. Here are some notes to help others who run into the same issue.

The string attribute Alarm is set by Traccar when my device sends the message "TOWED" "DEF" or "BLP", two of which are incorrectly used by the device, so I create this computed attribute:

Attribute: alarm
Expression: alarm == "tow" ? null : (alarm == "powerCut" ? "tampering" : alarm)

You can find the various string values for Alarm in the source code. Then you can find your protocol decoders and check which alarms and other attributes are set.

As an aside, I wonder why Alarm is a string instead of an enum, because it would seem to prevent the Alarm attribute from holding multiple values simultaneously.

Anton Tananaev2 years ago

How would enum help with supporting multiple values?

jond2 years ago

If the Alarm attribute is numeric, the idea is to model each possible alarm as a different power of 2, then use bitwise operators to combine multiple alarms into the stored value of the attribute. But when the attribute is string, it can hold only one value. But this is not a criticism, as I expect I am not seeing something that you have considered when modelling the data.

jond2 years ago

I am not familiar with Java, but after a brief glance I think Java enums have a cumbersome syntax unlike other languages I know. So I would just use ints.

// basic alarm types
int ALARM_LOWBATTERY = 1;
int ALARM_TOW = 2;
int ALARM_POWERCUT = 4;
int ALARM_SOS = 8;
int ALARM_GEOFENCE = 16;
int ALARM_FUELLEAK = 32;

// set the alarm attribute using bitwise OR
int alarm = ALARM_LOWBATTERY | ALARM_TOW | ALARM_GEOFENCE; // 19

// check for a specific alarm type using bitwise AND
boolean isFuelLeak = (alarm & ALARM_FUELLEAK) != 0; // false
boolean isGeofence = (alarm & ALARM_GEOFENCE) != 0; // true

In this small example, the numeric value of the alarm attribute could be any integer from 1 to 63, and each of those values represents a unique combination of the basic alarm types.

Anton, would this be a useful feature for Traccar?

Anton Tananaev2 years ago

This has nothing at all to do with enums. You're just talking about one way for supporting multiple alarms, but it's actually not the best way. You're limited to 64 types. You can support basically unlimited number of alarms with a string.

jond2 years ago

Just to clarify, my original comment on enums was based on my experience with C/C++, but I now know Java enums are quite different. For anyone else who is interested, this is what it would have to look like for Java enums:

enum AlarmType {
    
    LowBattery(1), Tow(2), PowerCut(4), Sos(8), Temperature(16), Geofence(32), FuelLeak(64);

    public int value;    

    AlarmType(int value) {
        this.value = value;
    }
}

and each basic alarm would be written like AlarmType.FuelLeak.value which is cumbersome syntax, hence my suggestion above to just use ints instead.

Yes, the maximum value for an unsigned integer is (2^64)-1 so that would limit you to 64 basic alarm types, but looking at the Traccar source there are only 38 basic alarm types currently. I guess you expect to support more than 64 one day? If so, clearly this approach would not work.

But as long as you have 64 base types or less, the performance gains of these bitwise operations versus having to parse a string would be massive. Especially if that string could be the concatenation of more than 64 base type strings. I expect these performance gains would be valuable to clients with a large number of devices and frequent reporting intervals.

Thanks for your thoughts, Anton. And thanks also for being so visible and engaged with the Traccar community!