FHIR Observations Intro (My PHR)

(Kev Mayfield) #1

So what is my PHR? To be more accurate I should probably say what systems contribute to my PHR but I’ll start several years ago and build up to that.

It all started with a purchase of wifi enabled set of scales. As you can see from the screen shot below I’ve been recording my weight since 2014.

weight

My ideal weight is below 80kg, so although I wasn’t too far off in 2014 - getting married piled on the pounds (it’s also the same date I stopped smoking). So I decided to do some exercise in early 2015, oiled up my old bike and went exploring the local area. Well, I’m middle aged and you can guess what happened next from the tech point of view I got even more data (devices and bikes), which led to the popular strava app.

This screen shot is my training stress score.

It’s pretty clear to see the correlation of effort (TSS) matching weight loss (I’ve varied my diet and also muscle mass has increased), it’s not an exact match but it shows the trend and the effectiveness of the intervention.

The data displayed as graphs works well but it would be nicer to see the graphs side by side.

So I started looking at ways to write my own graphs both the scales withings and strava have API’s for accessing the data, so it’s possible. Both use RESTful JSON and secure their endpoints using OAuth2, so it was possible. I decided to use FHIR, firstly FHIR used the same observation model I’d used in the 90’s working for a GP supplier and secondly it was JSON, restful and OAuth2 same as the project I was working on for NHS Digital.

I’m not going to go into detail on the API’s, they are well documented and several examples can be found in GitHub. What did instead was to use the download my data as CSV option, convert that to FHIR and store the data on the CCRI. Example CSV files can be found here: careconnect-cli/src/main/resources/Examples/nokia at master · nhsconnect/careconnect-cli · GitHub

It doesn’t say it but all the values are in Kg or put another way the units are Kg. I’m now going to convert this to FHIR, we will use the level 1 Care Connect profile (I’m not a fan of multiple profiles for Observations, I differentiate between obs via code, not profile name). Looking at the profile we need include a code for our obs, NHS prefers to use SNOMED and looking at a SNOMED browser I found 27113001 to represent Body Mass [I choose that code because it was an Observable Entity and other standards such as openEHR had also used this code. I used https://snomedbrowser.com to search for the code as it’s less featured and so easier to navigate]

I used patient 2 on the Care Connect Reference Implementation as the fake me and if you search for Patient 2 and code = 27113001 (copy query below into postman)

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?patient=2&code=27113001

The resources don’t say they conform to CareConnect-Observation-1 but they are (they were done before the profile was curated. You can test this via the validation tools if you want).

Although I wanted to just use SNOMED codes this was impossible, looking at this date search

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?patient=2&date=gt2017-09-23

You will notice I had to use LOINC codes for daily steps and calories burned, this is a limitation of SNOMED. Someone with a clinical coding background can better explain this but I think it’s something to do with these values being classed as therapy measures. [As a developer I would normally ask the clinical coding team for the correct codes and units to use.]

The code behind this CSV import can be found in this project: GitHub - nhsconnect/careconnect-cli: Command line tools for CCRI/FHIR Server including sample data population.

So far I’ve discussed converting my PHR data converted into FHIR resources and then stored in a SQL database (CCRI). As an application developer this is great, I only need to understand one API and as the data is returned in a standard structure I can minimise the amount of code I need to write.

Modern Data Exchanges

The traditional way of exchanging data within the NHS is to send a message complete with all the data but with some PHR feeds that’s not going to be practicable, the amount of data can be quite large. e.g. I’ve just completed the Tour De Yorkshire sportive and it created a lot of PHR data (6 Mb):

A lot of it is probably not required outside of strava, the max and average heart rate may be useful but that depends on who is looking at the data.
What these PHR apps do instead of messaging all the data is they allow you register for notifications, so when an exercise is completed your system gets a notification. What you do then is up to you, you may query the PHR to get some specific data items or just record an exercise has taken place (the data can always be retrieved when wanted). Either way it’s a lot easier than discussing what data items should be in the message (which can take time).

It’s not just MAMIL fitness apps producing vast amounts of PHR data. My other half was recently working on NHS app based diabetes treatment, GP’s and other clinician didn’t want detailed records they wanted a summary (DiagnosticReport?) [Neither did they want a PDF delivered via NHS.Net but guess what happened… ]

So should all PHR’s should have a open API (ideally FHIR based) and a system of sending notifications.

More Complex Observations

Observations are not always as simple as I mentioned above, quite often they are a code(/type), value and a date but some are more complex. For example blood pressure consists of two values: systolic and diastolic. Their are several on the CCRI, to identify them I used this profile https://fhir.hl7.org.uk/STU3/StructureDefinition/CareConnect-BloodPressure-Observation-1 looked at the section for code and found 75367002
I then searched the CCRI for entries with this code:

https://data.developer.nhs.uk/ccri-fhir/STU3/Observation?code=75367002

Note the results are returned using the level 1 profile not the BloodPressure profile, this is still valid.

{
"resourceType": "Observation",
"id": "10827",
"meta": {
    "lastUpdated": "2019-01-20T16:34:41.837+00:00"
},
"status": "final",
"category": [
    {
        "coding": [
            {
                "system": "http://hl7.org/fhir/observation-category",
                "code": "vital-signs",
                "display": "Vital Signs"
            }
        ]
    }
],
"code": {
    "coding": [
        {
            "system": "http://snomed.info/sct",
            "code": "75367002",
            "display": "Blood pressure"
        }
    ]
},
"subject": {
    "reference": "Patient/1181",
    "display": "MS Lauren CORR"
},
"context": {
    "reference": "Encounter/724"
},
"effectiveDateTime": "2019-01-17T09:01:42+00:00",
"component": [
    {
        "code": {
            "coding": [
                {
                    "system": "http://snomed.info/sct",
                    "code": "72313002",
                    "display": "Systolic blood pressure"
                }
            ]
        },
        "valueQuantity": {
            "value": 129,
            "unit": "mm[Hg]",
            "system": "http://unitsofmeasure.org",
            "code": "mm[Hg]"
        }
    },
    {
        "code": {
            "coding": [
                {
                    "system": "http://snomed.info/sct",
                    "code": "1091811000000102",
                    "display": "Diastolic arterial pressure"
                }
            ]
        },
        "valueQuantity": {
            "value": 79,
            "unit": "mm[Hg]",
            "system": "http://unitsofmeasure.org",
            "code": "mm[Hg]"
        }
    }
]
}

Notice how this sub divides into components, each component has both code and value. I’ve not included the LOINC code as the server doesn’t know what it is, this doesn’t break validation rules (for bloodpressure or level 1 obs profiles).

Moving on from Observations with components we have sets of Observations or results based on a set of Observations:

FHIR DiagnosticReport

It has been suggested this is the correct resource to group PHR fitness observations but I’ve not looked in detail.

Summary

I’ve not done my app yet, still working on it. I’ve now got other data such as Heart Rate Variability (Apple) and Pulse Wave Velocity (just been reactivated on withings scale) to explore… HRV seems to be telling me when I’m about to become sick but at the moment it’s saying I’m fit to go out on my bike … so

1 Like
(Rik Smithies) #2

fantastic, inspiring stuff Kevin.

one comment on this:

(I’m not a fan of multiple profiles for Observations, I differentiate between obs via code, not profile name)

That is right. It is only the code that differentiates. We shouldn’t use profiles for this. It wouldn’t be correct to search by asking for all data that is tagged with a profile, for instance. The real semantics are in the code, and the profile is just a statement of requirements for data capture (unless your search also validates dynamically against the profile, which I have heard suggested lately but is something totally different).