FHIR Chat · Auto entry of PHD data into QR · questionnaire

Stream: questionnaire

Topic: Auto entry of PHD data into QR


view this post on Zulip Brian Reinhold (Dec 11 2021 at 17:19):

@Lloyd McKenzie @Brian Postlethwaite This thread is a continuation. Inspired by the last SDC WG call. It is rather long....

The use case is quite simple:
A patient in a home environment retrieves a questionnaire that instructs the patient to take a measurement with a communicating Personal Health Device. For the moment I am going to ignore the cases of what happens if the device does not exist, doesn't work, or other related problems. So the patient takes the measurement, and the desired data is automatically entered into the QR and the QR is automatically linked to the FHIR Observations generated from the PHD. So the QR contains BOTH the measurement values and the links. Based upon use cases in the field, there is a strong desire to have both - the 80% use case looking at 'trusted' input data in the answers (not manually entered). The other 20% for when further details are needed and the full Observation resources have to be accessed.

The Questionnaire may also 'pop up' in response to a measurement taken; in other words, it is resident on the application host and triggered under the right conditions.

How would I do this? Without knowing about any other IG or workflow this is what I would do

  • Hidden with that faithful question in the questionnaire would be a set of MDC (Medical Device Codes) that would specify
    • the device type
    • the measurements desired
    • device information desired
      I am assuming there is some way to attach those codes to the Questionnaire question that the patient would not have to know about.

The patient would take the measurement. Clearly the application must be able to extract information from the questionnaire and it must be able to communicate with the PHDs and decode that data. Since PHDs provide the MDC codes, such an application could

  • validate the device type
  • select the desired measurements
  • select the desired device information

given that the Questionnaire has the MDC codes.

Now what? At this point the application only consists of language objects or structs representing the QR and the PHDData. The application is already capable of generating the Observation and Device resources from the PHDData based upon the PHD IG. What is new is creating the QR resource and filling in that QR answer with the values from the PHDData and linking that QR answer to the Observation and Device resources generated by the PHDData.

The way I actually did this was to create a transaction Bundle with the PHDData resources following the PHD IG with the addition of the QR. The QR answer would reference the relevant Observations in the Bundle and it would have the desired values in answers. The QR would have both. Of course, all references are temporary at this time and will not be resolved to their final state until the transaction is processed at the server.

The entire sequence except perhaps the retrieval of the Questionnaire and the final upload could happen offline. Connectivity in some countries and locations is either spotty or expensive or both.

Now that is how I would do it having complete ignorance about any other work flows.

What I would like to request is how to handle such a use case making use of SDC workflows.

view this post on Zulip Lloyd McKenzie (Dec 12 2021 at 00:37):

A Questionnaire "popping up" is completely outside of the SDC space. SDC only comes into play once a user is already filling out a Questionnaire. Within a Questionnaire, I think the only piece needed is an extension that essentially says 'populate now' which could appear on the context elements to be retrieved. The form filler can grab them from a device directly, allow the user to select them from a local file on their system or grab recent data from the server. Once the observation(s) for that group have been grabbed, they can serve as answers to questions and/or have information extracted from them to answer questions. Whether those answers are hidden, read-only or editable would be up to the form designer

view this post on Zulip Brian Reinhold (Dec 15 2021 at 15:10):

@Lloyd McKenzie That aside how would one pose the question? Should one create a group where the code is the MDC code base for specializations? This code would indicate to the renderer that this group is related to getting data from a communicating PHD.

view this post on Zulip Lloyd McKenzie (Dec 15 2021 at 20:11):

You'd have a code (MDC or otherwise) on the relevant questions within the Group that had the 'trigger' extension on it. When a user invoked the trigger, the client would do its best to fill the questions as best it could. If it knows that a particular device provides data for a particular MDC, LOINC, or some other code, then it can hit the device for that data.

view this post on Zulip Brian Reinhold (Dec 20 2021 at 13:23):

@Lloyd McKenzie
In last Thursday's meeting for SDC you mentioned this extension set to specify behavior

  <extension url="real-time-collection">
    <extension url="code">
      <valueCoding>
      ...
      </valueCoding>
    </extension>
    <extension url="name">
      <valueString value="variable123">
    </extension>
  </extension>
  <extension url="real-time-collection">
    ...
  </extension>

What was the purpose of the 'name' extension? I understand the 'code' extension as being the set of codes that are going to instruct the renderer which device types and which measurements to autopopulate and link to the QR. But I don't recall the purpose of the 'name'.

view this post on Zulip Lloyd McKenzie (Dec 20 2021 at 15:20):

The name is what exposes what's been retrieved for subsequent use in FHIRPath to populate question answers and/or control Questionnaire logic.

view this post on Zulip Brian Reinhold (Dec 21 2021 at 15:36):

@Lloyd McKenzie Little confused there. I will submit some attempts. I have finally implemented support for Q and QRs in my gateway.

view this post on Zulip Brian Reinhold (Jan 04 2022 at 18:29):

@Lloyd McKenzie I have created two questionnaire entries but I am a little unsure of what the name case should do

Here is the extension variant

{
  "resourceType": "Questionnaire",
  "item": [
    {
      "extension": [
        {
          "extension": [
            {
              "url": "mdc-device-code",
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "528391",
                    "display": "MDC_DEV_SPEC_PROFILE_BP"
                  }
                ]
              }
            },
            {
              "url": "mdc-msmt-code",
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "150021",
                    "display": "MDC_PRESS_BLD_NONINV_SYS"
                  }
                ]
              }
            },
            {
              "url": "name",
              "valueString": "Some Name"
            }
          ],
          "url": "real-time-collection"
        }
      ],
      "text": "Get the Systolic pressure from your Blood pressure device",
      "type": "group",
      "item": [
        {
          "text": "When the systolic blood pressure value has been received it will be automatically entered into the response",
          "type": "display"
        },
        {
          "linkId": "BP.sys",
          "code": [
            {
              "system": "urn:iso:std:iso:11073:10101",
              "code": "150021",
              "display": "MDC_PRESS_BLD_NONINV_SYS"
            }
          ],
          "text": "The device data systolic pressure will be automaticially entered",
          "type": "quantity",
          "item": [
            {
              "linkId": "BP.sys.Ref",
              "text": "The Observation resource reference for the systolic pressure will beautomatically entered",
              "type": "reference"
            }
          ]
        }
      ]
    }
  ]
}

And here is one without using extensions that I was originally thinking

{
  "resourceType": "Questionnaire",
  "item": [
    {
      "code": [
        {
          "system": "urn:iso:std:iso:11073:10101",
          "code": "528391",
          "display": "MDC_DEV_SPEC_PROFILE_BP"
        }
      ],
      "text": "Take a measurement with your Blood pressure device",
      "type": "group",
      "item": [
        {
          "text": "When the systolic blood pressure value has been received it will be automatically entered into the response",
          "type": "display"
        },
        {
          "linkId": "BP.sys",
          "code": [
            {
              "system": "urn:iso:std:iso:11073:10101",
              "code": "150021",
              "display": "MDC_PRESS_BLD_NONINV_SYS"
            }
          ],
          "text": "The device data systolic pressure will be automatically entered",
          "type": "quantity",
          "item": [
            {
              "linkId": "BP.sys.Ref",
              "text": "The Observation resource reference for the systolic pressure will be automatically entered",
              "type": "reference"
            }
          ]
        }
      ]
    }
  ]
}

view this post on Zulip Lloyd McKenzie (Jan 04 2022 at 21:44):

I wouldn't use an extension called "deviceCode". What you're really wanting to do is say "go get the following observation and store it in variable X". The extension shouldn't be specific to observations coming from devices and definitely shouldn't be specific to mdc.

view this post on Zulip Brian Reinhold (Jan 04 2022 at 22:02):

@Lloyd McKenzie Is that where the 'name' extension comes in? It tells the name of the variable to store it in, for example valueQuantity? I am trying to link the pieces together. Still not quite sure what you have in mind. What I have as the two mdc codes should be one code which is to tell my application the specifics of the real time collection. When the application sees the MDC codes in the valueCodeableConcept that indicates this is to get data from a PHD. The name extension will have in the valueString 'valueQuantity'?

view this post on Zulip Lloyd McKenzie (Jan 04 2022 at 23:28):

You'll have a complex extension with two child extensions - one with a valueString (name) and one with a valueCoding (observationCode).

view this post on Zulip Brian Reinhold (Jan 05 2022 at 11:52):

@Lloyd McKenzie @Brian Postlethwaite Does this capture the idea?

{
  "resourceType": "Questionnaire",
  "item": [
    {
      "extension": [
        {
          "extension": [    // Lists the items to be collected.
            {               // There is no 'link-id-for-collectable' extension which means the PHD info is not
                            // collected.
              "url": "collectable-item",    // This entry tells the application which type of PHD is to be used
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "528391",
                    "display": "MDC_DEV_SPEC_PROFILE_BP"
                  }
                ]
              }
            },
            {
              "extension": [    // Lists where to put the results. There will be two locations for the results
                {
                  "url": "link-id-for-collectable",    // The first location is given by the answer type in link-id 'BP.sys.Quant'
                  "valueString": "BP.sys.Quant"        // which is of type 'valueQuantity' and therefore the systolic value
                },                                     // and units retrieved from the PHD can be loaded
                {
                  "url": "link-id-for-collectable",    // The second location is given by the answer type in link-id BP.Observation.Ref
                  "valueString": "BP.Observation.Ref"  // which is of type Reference. The Observation Resource for the BP msmt will go
                }                                      // here
              ],
              "url": "collectable-item",    // This entry tells the application which msmt is to be collected
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "150021",
                    "display": "MDC_PRESS_BLD_NONINV_SYS"
                  }
                ]
              }
            }
          ],
          "url": "real-time-collection"
        }
      ],
      "text": "Get the Systolic pressure from your Blood pressure device",
      "type": "group",
      "item": [
        {
          "text": "When the systolic blood pressure value has been received it will be automatically entered into the response",
          "type": "display"
        },
        {
          "linkId": "BP.sys.Quant",
          "text": "The device data systolic pressure will be automatically entered",
          "type": "quantity",
          "item": [
            {
              "linkId": "BP.Observation.Ref",
              "text": "The Observation resource reference for the systolic pressure will be automatically entered",
              "type": "reference"
            }
          ]
        }
      ]
    }
  ]
}

The 'real-time-collectable' extension has two 'collectable-item' sub-extensions indicating what is to be collected. The 'collectable-item' sub-extension has itself two 'link-id-for-collectable' extensions indicating where to put the collectable item. The first collectable-item sub extension has no 'link-id-for-collectable' extension since there is no device information that is to be inserted into the answer.

Perhaps a better approach would be to have three collectable item sub extensions, one for the device, the other for the msmt, and the third for the Observation resource. Something like this:

{
  "resourceType": "Questionnaire",
  "item": [
    {
      "extension": [
        {
          "extension": [
            {
              "url": "collectable-item",
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "528391",
                    "display": "MDC_DEV_SPEC_PROFILE_BP"
                  }
                ]
              }
            },
            {
              "extension": [
                {
                  "url": "link-id-for-collectable",
                  "valueString": "BP.sys.Quant"
                }
              ],
              "url": "collectable-item",
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "urn:iso:std:iso:11073:10101",
                    "code": "150021",
                    "display": "MDC_PRESS_BLD_NONINV_SYS"
                  }
                ]
              }
            },
            {
              "extension": [
                {
                  "url": "link-id-for-collectable",
                  "valueString": "BP.Observation.Ref"
                }
              ],
              "url": "collectable-item",
              "valueCodeableConcept": {
                "coding": [
                  {
                    "system": "http://hl7.org/fhir/",
                    "code": "observation.html"
                  }
                ],
                "text": "FHIR Observation resource"
              }
            }
          ],
          "url": "real-time-collection"
        }
      ],
      "text": "Get the Systolic pressure from your Blood pressure device",
      "type": "group",
      "item": [
        {
          "text": "When the systolic blood pressure value has been received it will be automatically entered into the response",
          "type": "display"
        },
        {
          "linkId": "BP.sys.Quant",
          "text": "The device data systolic pressure will be automatically entered",
          "type": "quantity",
          "item": [
            {
              "linkId": "BP.Observation.Ref",
              "text": "The Observation resource reference for the systolic pressure will be automatically entered",
              "type": "reference"
            }
          ]
        }
      ]
    }
  ]
}

A total aside - I kind of wish extensions were last in some sense so that the sub-extensions appeared under the extension. But I can also see why they are first. In the end, the machine doesn't care, only us human readers of JSON and XML care.

view this post on Zulip Lloyd McKenzie (Jan 05 2022 at 19:06):

I would expect your base extension would be "http://hl7.org/fhir/someIg/StructureDefinition/real-time-collection". It would have two child extensions called "name" (valueString) and "code" (valueCoding). There's no need to deal with linkIds at all in this extension. In child elements you'd use %someName (the value from the 'name' child extension) as part of initialValueExpression extensions.

view this post on Zulip Brian Reinhold (Jan 05 2022 at 20:18):

@Lloyd McKenzie Could you give me an example of what you are thinking?

view this post on Zulip Lloyd McKenzie (Jan 05 2022 at 20:30):

{
  "extension": [
    {
      "url": "http://hl7.org/fhir/someig/StructureDefinition/real-time-collection",
      "extension": [
        {
          "url": "code",
          "valueCoding": {
            "system": "urn:iso:std:iso:11073:10101",
            "code": "528391"
          }
        },
        {
          "url": "name",
          "valueString": "BP"
        }
      ]
    }
  ]
}

You'd then refer to %BP in the initialExpression or other extensions

view this post on Zulip Brian Reinhold (Jan 06 2022 at 13:05):

@Lloyd McKenzie Let's see how far I get.
The rendering application obtains the Questionnaire
The rendering application creates a Questionnaire Response

  • The app comes across the real time entry extension
  • It sees the code extensions to see what real time information it is to collect
  • It looks at the name information for each code entry. If the valueString is not empty, the application is going to get the information represented by the code
  • The user takes the measurement
  • The application collects the data as indicated by the code entries

Now what? These collected values are answers to questions. I don't know where to put the answers without some link-id telling me what question a given retrieved code entry is to answer. If the name valueString had the link id I would know what question the retrieved value is to answer.

I still do not know how my application is to create the QR given the Q. I think there are some assumptions here I am unaware of.

view this post on Zulip Lloyd McKenzie (Jan 06 2022 at 16:56):

After collection, the Observation collected becomes available in memory to calculatedExpression, initialExpression and other expressions within the Questionnaire, which allows the rendering application to populate question answers and/or control Questionnaire behavior based on the information retrieved. Have you read through the SDC section on population and advanced behavior?

view this post on Zulip Brian Reinhold (Jan 06 2022 at 22:18):

@Lloyd McKenzie Okay, now I think I see the issue. I do not have the Observation resource yet and have not created it. It will be created along with the QR and uploaded in a Bundle together. This makes providing references much easier. It will also provide all the other Observations (including the Coincident Time Stamp Observation) and Device Resources related to the Observation and they will be including in the Bundle. The upload may not occur immediately after the QR is done as there may be no connectivity.

I have not read through that section (maybe I have but at the time I looked at it I had no context with respect to this behavior).

view this post on Zulip Lloyd McKenzie (Jan 06 2022 at 23:01):

My expectation is that the real-time-measurement would have to produce the Observation resource and make it available "real-time" and would prompt the user to click something once it was expected to be available so the software could go grab it and make it available to the rest of the decision logic. If/whether it subsequently gets packaged up in a transaction Bundle is a side-point. The render needs to have access to it in memory if it's going to use the data to answer questions.

view this post on Zulip Diane (Jan 06 2022 at 23:14):

If you can't/won't have the Observation resource created yet in your flow, you could try something similar to my https://chat.fhir.org/#narrow/stream/179255-questionnaire/topic/Linking.20PHD.20data.20to.20Questionnaire.20Response/near/262006099 suggestion for the design, where the Observation is created later in the process flow.

view this post on Zulip Brian Reinhold (Jan 13 2022 at 19:42):

@Diane The use case we have is that a patient receives a questionnaire which prompts him/her to take a measurement with a communicating personal health device (say a blood pressure cuff). There is information in the questionnaire that tells the rendering application that a measurement is going to be taken with a blood pressure cuff (MDC_DEV_SPEC_PROFILE_BP) and report a set of values when the measurement is received (MDC_PRESS_BLD_NONINV_SYS, MDC_PRESS_BLD_NONINV_DIA - systolic and diastolic pressures). These codes are provided by the device so the renderer will be able to identify the device (that it is the correct one) and get the desired measurements from it (these devices often report pulse rate as well but in this case it is not being asked for).

The render is on a gateway that is able to decode measurements from PHDs and can convert these measurements to FHIR following the PHD IG.

At this point the renderer can create the Questionnaire Response object and populate the answer fields to the question with the correct answers. When the patient completes the questionnaire, the renders passes the QR object and Measurement and Device object to the Fhir creator. The FHIR creator creates the Device, Patient, Observation and QuestionnaireResponses and packs them into a Bundle. This creation adds a reference to the Observations in the QR which already contains the values. So the QR contains both, the systolic and diastolic values in the answer and references to the Observation resources. The transaction Bundle is serialized and uploaded.

If connectivity is bad and the upload can't be made at the current time, the serialized Bundle is saved and uploaded at a future time when connectivity is restored.

That's the idea in any case.

view this post on Zulip Diane (Jan 13 2022 at 21:54):

It seems like Lloyd McKenzie's proposed flow of creating the Observation resource at the time of the measurement might be closer to what you need. As Lloyd said, the Observation can be created but not packaged into the transaction Bundle until later.

view this post on Zulip Brian Reinhold (Jan 13 2022 at 22:03):

@Diane Basically that is what I am doing - but a final serialized resource does not get created until upload. Its just an object that is converted to resources at the time of upload.

view this post on Zulip Lloyd McKenzie (Jan 13 2022 at 23:19):

Right. You'll have to move that timeline forward if you want to access the data in a Questionnaire in a non-proprietary way.

view this post on Zulip Brian Reinhold (Jan 18 2022 at 15:29):

@Lloyd McKenzie Should the valueString in the name extension be a FHIR path to the resource element? For example, in the case of the device specialization it would be 'Device.specialization.systemType.where(coding.system='urn:iso:std:iso:11073:10101').coding.code'
That would point you to the specialization code which should be that in the 'code' extension.

view this post on Zulip Brian Reinhold (Jan 18 2022 at 15:31):

So I guess the work flow is after the user takes the measurement, the Device and Observation resources are created, the the renderer accesses the values from the created resources.

view this post on Zulip Lloyd McKenzie (Jan 18 2022 at 16:39):

No. In FHIRPath, a value[x] element just has a name of .value. If you want to filter, I believe you can say .value as string.

view this post on Zulip Brian Reinhold (Jan 18 2022 at 21:11):

@Lloyd McKenzie

Okay, with respect to the nested extensions I guess the way to do it is to place the real time extension pairs is in each individual item.

I still am unsure how to use the 'name' extension so I placed the FHIR path to the resource value (assumption is that the resource exists) in the valueString element that the renderer would use to get the value and place it in the item answer for the QR. In some sense, assuming the resources exist, the 'code' extension seems almost superfluous. In any case. The Questionnaire looks like this:

{
  "resourceType": "Questionnaire",
  "item": [
    {
      "extension": [
        {
          "extension": [
            {
              "url": "code",
              "valueCoding": {
                "system": "urn:iso:std:iso:11073:10101",
                "code": "528391",
                "display": "MDC_DEV_SPEC_PROFILE_BP"
              }
            },
            {
              "url": "name",
              "valueString": "Device.specialization.systemType.where(coding.system='urn:iso:std:iso:11073:10101').coding.code"
            }
          ],
          "url": "http://hl7.org/fhir/something/StructureDefinition/real-time-collection"
        }
      ],
      "text": "Get the Systolic and diastolic pressure from your Blood pressure device",
      "type": "group",
      "item": [
        {
          "text": "Please take a measurement with your communicating Blood Pressure Device",
          "type": "display",
          "item": [
            {
              "extension": [
                {
                  "extension": [
                    {
                      "url": "code",
                      "valueCoding": {
                        "system": "http://hl7.org/fhir/",
                        "code": "observation.html"
                      }
                    },
                    {
                      "url": "name",
                      "valueString": "Observation.id"
                    }
                  ],
                  "url": "http://hl7.org/fhir/something/StructureDefinition/real-time-collection"
                }
              ],
              "linkId": "BP.Observation.Ref",
              "text": "Enter the reference to the Observation resource for the blood pressure. (It will be automatically entered)",
              "type": "reference",
              "item": [
                {
                  "extension": [
                    {
                      "extension": [
                        {
                          "url": "code",
                          "valueCoding": {
                            "system": "urn:iso:std:iso:11073:10101",
                            "code": "150021",
                            "display": "MDC_PRESS_BLD_NONINV_SYS"
                          }
                        },
                        {
                          "url": "name",
                          "valueString": "Observation.component.where(code.coding.where(code='150021')).value"
                        }
                      ],
                      "url": "http://hl7.org/fhir/something/StructureDefinition/real-time-collection"
                    }
                  ],
                  "linkId": "BP.sys.Quant",
                  "text": "Enter the systolic pressure (It will be automatically entered)",
                  "type": "quantity"
                },
                {
                  "extension": [
                    {
                      "extension": [
                        {
                          "url": "code",
                          "valueCoding": {
                            "system": "urn:iso:std:iso:11073:10101",
                            "code": "150022",
                            "display": "MDC_PRESS_BLD_NONINV_DIA"
                          }
                        },
                        {
                          "url": "name",
                          "valueString": "Observation.component.where(code.coding.where(code='150022')).value"
                        }
                      ],
                      "url": "http://hl7.org/fhir/something/StructureDefinition/real-time-collection"
                    }
                  ],
                  "linkId": "BP.dia.Quant",
                  "text": "Enter the diastolic pressure (It will be automatically entered)",
                  "type": "quantity"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Not sure if I am beginning to get your approach or not, but if I need to have the situation that the resource exists, having the FHIR path is certainly a great way to tell the renderer where to get the needed value for the answer. So I assume the work flow would be that the extension in the group would tell the renderer that the answers in this group are going to be a real-time collection and the code extension says that it is a BP cuff. The name extension gives the location of the specialization code. Since we are not getting any data from the Device resource its probably best NOT to have the name extension here.

For the remaining item entries the name and code extensions tell the renderer what to get and where to get it (except the location of the resource is not specified)

view this post on Zulip Lloyd McKenzie (Jan 19 2022 at 04:29):

The name should be short. E.g. "Diastolic". You'll reference it later extensions as "%Diastolic". You don't want it to be long and it definitely can't have any periods in it.


Last updated: Apr 12 2022 at 19:14 UTC