project Utilities / zepp_to_influxdb avatar

utilities/zepp_to_influxdb#2: Capture blood oxygen levels



Issue Information

Issue Type: issue
Status: closed
Reported By: btasker
Assigned To: btasker

Milestone: 0.3
Created: 03-Aug-23 14:41



Description

The Bip 30 Pro can capture SpO2 levels overnight.

The requests that the Zepp Life app make to retrieve this data can be recreated with

band_data_url=f"https://api-mifit-de2.zepp.com/users/{auth_info['token_info']['user_id']}/events"
headers={
        'apptoken': auth_info['token_info']['app_token'],
}
get_data={
        "limit" : 1000,
        "from" : '0',
        "to" : '1691103600000',
        "eventType" : "blood_oxygen",
        "subType" : "odi",
        "timeZone" : "Europe/London"
}

The response looks like this

{
  "items": [
    {
      "userId": "<redacted>",
      "eventType": "blood_oxygen",
      "subType": "odi",
      "timestamp": 1690930800000,
      "valid": "2",
      "score": "94",
      "cost": "26021",
      "dispCode": "1",
      "odi": "3.1820452",
      "appName": "com.huami.midong",
      "timezone": "Europe/London",
      "deviceSource": "256",
      "sn": "<redacted>",
      "deviceId": "<redacted>",
      "version": "3.0.0.4",
      "odiNum": "23"
    },
    {
      "userId": "<redacted>",
      "eventType": "blood_oxygen",
      "subType": "odi",
      "timestamp": 1691017200000,
      "valid": "2",
      "score": "97",
      "cost": "23920",
      "dispCode": "1",
      "odi": "1.3545151",
      "appName": "com.huami.midong",
      "timezone": "Europe/London",
      "deviceSource": "256",
      "sn": "<redacted>",
      "deviceId": "<redacted>",
      "version": "3.0.0.4",
      "odiNum": "9"
    }
  ]
}

ODI is Oxygen Desaturation Index. Because the request's subType" param isodi` the API is reporing events where the score was low enough to indicate possible Hypopnea.

The API can also be called without subType specified

band_data_url=f"https://api-mifit-de2.zepp.com/users/{auth_info['token_info']['user_id']}/events"
headers={
        'apptoken': auth_info['token_info']['app_token'],
}
get_data={
        "limit" : 1000,
        "from" : '0',
        "to" : '1691103600000',
        "eventType" : "blood_oxygen",
        "timeZone" : "Europe/London"
}

Which results in a much more verbose response, with another event type also reported

    {
      "userId": "<redacted>",
      "eventType": "blood_oxygen",
      "subType": "osa_event",
      "timestamp": 1690932624000,
      "timezone": "Europe/London",
      "extra": "{\"appName\":\"com.huami.midong\",\"deviceId\":\"<redacted>\",\"deviceSource\":256,\"hr\":[],\"sn\":\"<redacted>\",\"spo2\":[],\"spo2_decrease\":4,\"timezone\":\"Europe/London\",\"timestamp\":1690932624000,\"version\":\"3.0.0.4\"}"
    }

It doesn't seem to report SpO2 levels, only when they've dropped.



Issue Links

Toggle State Changes

Activity


assigned to @btasker

It looks like there's also a subType value of click - the app queries (although I don't get any events back).

The watch has a "Measure Now" option for SpO2, so I'm guessing hitting that results in those.

The current implementation of this creates a couple of new series.

ODI events:

    return {
        "timestamp": int(record['timestamp']) * 1000000, # Convert to nanos 
        "fields" : {
            "odi_read" : float(record['odi']),
            # Not sure what this is, skipping for now 
            # (I *think* it might just be a record ID)
            # "odi_number" : int(record['odiNum']),
            #
            # There are also "cost" and "valid"
            "score" : float(record['score']),
            },
        "tags" : {
            "blood_event" : "odi"
            }
    }  

OSA Events

    return {
        "timestamp": int(record['timestamp']) * 1000000, # Convert to nanos 
        "fields" : {
            "spo2_decrease" : float(osa_record['spo2_decrease']),
            },
        "tags" : {
            "blood_event" : "osa"
            }
    } 
verified

mentioned in commit e61b6526057ff0d696cf664171ce15829aa788ac

Commit: e61b6526057ff0d696cf664171ce15829aa788ac 
Author: B Tasker                            
                            
Date: 2023-08-03T17:43:52.000+01:00 

Message

Collect information on blood oxygen events (utilities/zepp_to_influxdb#2)

This collects any events that the API reports for blood_oxygen levels.

Currently that's

  • odi: a measure of how many times an hour oxygen levels drop
  • osa: An event of suspected Obstructive Sleep Apnea
+86 -1 (87 lines changed)

I'm not going to close this yet - I've just triggered a manual read from the watch, I'll check later to see whether we get a click event type (or something else) reported.

No sign of any new events yet.

The app is showing it though, suggesting it must be available through some endpoint or the other.

I think we close this as done for now - if further MiTMing reveals an endpoint that can be used to capture other measurements we can raise a seperate tickets for that.

I've had a click event turn up, will raise a ticket for it later

mentioned in issue #6

marked this issue as related to #6