Wiki: Heart Rate Data Format/Utilities / zepp_to_influxdb



The way that the Zepp API exposes heart-rate measurements is quite different to other metrics.

The original exploration can be found in issue 4

The detail query_type of the API endpoint band_data.json (for example https://api-mifit-de2.zepp.com/v1/data/band_data.json) returns JSON of the following form

{
  "code": 1,
  "message": "success",
  "data": [
    {
      "uid": "<redacted>",
      "data_type": 0,
      "date_time": "2023-08-01",
      "source": 256,
      "summary": "aGVsbG8gd29ybGQ=",
      "uuid": "null",
      "data": "aGVsbG8gd29ybGQ=",
      "data_hr" : "aGVsbG8gd29ybGQ=",
   },
    {
      "uid": "<redacted>",
      "data_type": 0,
      "date_time": "2023-08-02",
      "source": 256,
       "summary": "aGVsbG8gd29ybGQ=",
      "uuid": "null",
      "data": "aGVsbG8gd29ybGQ=",
      "data_hr" : "aGVsbG8gd29ybGQ=",
   },
 ]
}

Note: Whilst also base64 encoded, the attribute summary is a base64 encoded JSON string and so the following does not apply to it.

The attributes data and data_hr are both base64 encoded bytestrings, representing a stream of values. It's not currently known what data represents.

For example, when base64 decoded, data_hr might look like this (it's a partial day's read)

ben@optimus:~/tmp/zepp$ xxd -ps /tmp/blob2 
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe
fefefefefefefefefefefefefefefefefeffffffff59ffffffffffffff5c
4c466effffff5e5f5c606b61504cff605eff7775724e5e494c57ff676469
6d64646fff6063ffffffff53ffffffffffffff525b67484b5763ffffffff
5262ff53ffffffffffffff53ffffffffffffffffff4affffffffffffffff
ff43ffffffffffffffffff53ffffffffffffffffff54ffffffffffffffff
ff3cffffffffffffffffff4bffffffffffffffffff4bffffffffffffffff
ff53ffffffffffffffffff52ffffffffff5d61ffff69ffff69ff61ffffff
ff59ffffff5e51ff77ffff5d606c6b6052ffff694969ffffffffffffffff
ff45ffffffffffffffffff6affffff7b46ffffffff435152ffffffffffff
ff78ffffffffffffff48ff70ffff47ffffffffffff49ffffffffff4b3cff
ff69ffffffffffffffffff68ffffffffffffffffff62ffffffff7877ffff
ff48ffffff71ffffffffff63ffffffff71ffffffff69ffffffff6aff8062
5affff44ffff7affffffff6affffffffffffffffff39ffffffffffffffff
ff5bffffffffffffffffff49ffffffffffffffffff63ffffffffffffffff
ff53ffffffffffffffffff62ffffffffffffffffff69ffffffffffffffff
ff60ffffffffffffffffff62ffffffffffffffffff62ffffffffffffffff
ff54ffffffffffffffffff5affffffffffffffffff5bffffffffffffffff
ff52ffffffffffffffffff52ffffffffffffffff595c5c5dff4a6468716e
4d5b65726f4f596465686559606b646a70747a7e7f7f808176797d7a7b79
7b807e7c7871777a5760666f737a7b7a7b7d7e7a7c7d7b7a484effffffff
ff59ffffffffffffffffff53ffffffffffffffffff4bffffffffffffffff
ff59ffffffffffffffffff5affffffffffffff69675affffffffffffffff
ff4bffffff494c6971ffff5affffffffffffffffff5affffffffffffff66
6963ffffffffffffffffff5affffff777548ffffff5f636675ffffffffff
ff62ffffffffffffffffff5affffffffffffffffff62ffffffffffffffff
ff61ffffffffffffffffff5bffffffffffffffffff5cffffffffffffffff
ff5affffffffffffffffff61ffffffffffffffffff62ffff6e484bff7874
ff6affffffffffffffffff4dffffffffff534e524d525854534d56545353
535453585a55534e4c57544e4c51534e514d515253534e4c4b5152584f4c

The values are of type short so each value is comprised of two bytes.

adjusted_vals = []
x = 1
b=b''
with open("/tmp/blob2", "rb") as f:
    while(byte := f.read(1)):
        x += 1
        b += byte
        if x == 2:
            # Reset the counter
            x = 1

            # Convert to an int
            v = int(b.hex(), 16)
            adjusted_vals.append(v)
            b = b''

print(adjusted_vals)

Reading the blob above gives

[254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 89, 255, 255, 255, 255, 255, 255, 255, 92, 76, 70, 110, 255, 255, 255, 94, 95, 92, 96, 107, 97, 80, 76, 255, 96, 94, 255, 119, 117, 114, 78, 94, 73, 76, 87, 255, 103, 100, 105, 109, 100, 100, 111, 255, 96, 99, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 82, 91, 103, 72, 75, 87, 99, 255, 255, 255, 255, 82, 98, 255, 83, 255, 255, 255, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 255, 255, 74, 255, 255, 255, 255, 255, 255, 255, 255, 255, 67, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 255, 255, 84, 255, 255, 255, 255, 255, 255, 255, 255, 255, 60, 255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 255, 255, 82, 255, 255, 255, 255, 255, 93, 97, 255, 255, 105, 255, 255, 105, 255, 97, 255, 255, 255, 255, 89, 255, 255, 255, 94, 81, 255, 119, 255, 255, 93, 96, 108, 107, 96, 82, 255, 255, 105, 73, 105, 255, 255, 255, 255, 255, 255, 255, 255, 255, 69, 255, 255, 255, 255, 255, 255, 255, 255, 255, 106, 255, 255, 255, 123, 70, 255, 255, 255, 255, 67, 81, 82, 255, 255, 255, 255, 255, 255, 255, 120, 255, 255, 255, 255, 255, 255, 255, 72, 255, 112, 255, 255, 71, 255, 255, 255, 255, 255, 255, 73, 255, 255, 255, 255, 255, 75, 60, 255, 255, 105, 255, 255, 255, 255, 255, 255, 255, 255, 255, 104, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 120, 119, 255, 255, 255, 72, 255, 255, 255, 113, 255, 255, 255, 255, 255, 99, 255, 255, 255, 255, 113, 255, 255, 255, 255, 105, 255, 255, 255, 255, 106, 255, 128, 98, 90, 255, 255, 68, 255, 255, 122, 255, 255, 255, 255, 106, 255, 255, 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 255, 255, 255, 255, 255, 255, 255, 91, 255, 255, 255, 255, 255, 255, 255, 255, 255, 73, 255, 255, 255, 255, 255, 255, 255, 255, 255, 99, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 255, 255, 255, 255, 255, 105, 255, 255, 255, 255, 255, 255, 255, 255, 255, 96, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 255, 255, 255, 255, 255, 84, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 255, 255, 91, 255, 255, 255, 255, 255, 255, 255, 255, 255, 82, 255, 255, 255, 255, 255, 255, 255, 255, 255, 82, 255, 255, 255, 255, 255, 255, 255, 255, 89, 92, 92, 93, 255, 74, 100, 104, 113, 110, 77, 91, 101, 114, 111, 79, 89, 100, 101, 104, 101, 89, 96, 107, 100, 106, 112, 116, 122, 126, 127, 127, 128, 129, 118, 121, 125, 122, 123, 121, 123, 128, 126, 124, 120, 113, 119, 122, 87, 96, 102, 111, 115, 122, 123, 122, 123, 125, 126, 122, 124, 125, 123, 122, 72, 78, 255, 255, 255, 255, 255, 89, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 89, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 105, 103, 90, 255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 73, 76, 105, 113, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 102, 105, 99, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 119, 117, 72, 255, 255, 255, 95, 99, 102, 117, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 255, 255, 255, 255, 255, 255, 255, 255, 255, 91, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 255, 255, 255, 255, 255, 255, 255, 255, 255, 90, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 255, 255, 255, 255, 255, 255, 255, 255, 255, 98, 255, 255, 110, 72, 75, 255, 120, 116, 255, 106, 255, 255, 255, 255, 255, 255, 255, 255, 255, 77, 255, 255, 255, 255, 255, 83, 78, 82, 77, 82, 88, 84, 83, 77, 86, 84, 83, 83, 83, 84, 83, 88, 90, 85, 83, 78, 76, 87, 84, 78, 76, 81, 83, 78, 81, 77, 81, 82, 83, 83, 78, 76, 75, 81, 82, 88, 79, 76]

Each datapoint represents a different minute of the day (with 1440 points in total).

The values 254 and 255 appear to indicate that no read was acquired at that time and should therefore be considered invalid (255 seems to indicate that it was a minute where a read was not required - usually because the watch is set to read every 10minutes/1hr/whatever).

As of utilities/zepp_to_influxdb#4 the zepp_to_influxdb script writes these values into field heart_rate