polyvertex / fitdecode

A FIT file parsing and decoding library written in Python3
MIT License
155 stars 33 forks source link

`timestamp_16` fields #28

Open Wilm0r opened 6 months ago

Wilm0r commented 6 months ago

I'm trying to decode whatever I can from the large "get all my data" zipfiles you can get from Garmin.

In the monitoring_b files you have a monitoring message that contains average heartbeat for that minute and a timestamp, but the timestamp is 16-bit, and a variant of the FIT-file 5-bit timestamp as described on https://developer.garmin.com/fit/protocol/ (search for 5-bit but you probably remember this anyway :) )

I've verified this is the 16-bit version of it, roughly, by comparing against an adjacent full timestamp (from a stress level message right before it):

97. monitoring
 * heart_rate: 54 [bpm]
 * timestamp_16: 50060 [s]
...
99. monitoring
 * activity_type: sedentary
 * current_activity_type_intensity: (8,)
 * intensity: 0
 * timestamp: 2017-06-18 23:41:00

$ printf "%x %x\n" $(($(TZ=0 date -d '2017-06-18 23:41:00' +%s)-631065600)) 50060
33a9c38c c38c

Shouldn't be hard for me to do the conversion but tracking the most recent full time from any recent field in the file will get a little ugly. Could your library do this more cleanly?

Wilm0r commented 6 months ago

Wrote this super simple data processor for now, which may or may not work well (I've not tested it around rollovers yet and it'll probably fail).

class Proc(fitdecode.processors.StandardUnitsDataProcessor):
    def process_type_date_time(self, reader, field_data):
        super().process_type_date_time(reader, field_data)
        last : datetime.datetime = field_data.value
        self.last_date = (int(last.timestamp()) - fitdecode.processors.FIT_UTC_REFERENCE) & ~0xffff

    def process_type_uint16(self, reader, field_data):
        if field_data.name == "timestamp_16":
            field_data.value |= self.last_date
            super().process_type_date_time(reader, field_data)