💫 WebSocket

Retrieving Observations from Kligo synchronously using a WebSocket client.

Server

ws://localhost:63336/

Channel

There is only one channel you can subscribe to: v3/Observation

The Channel v3/Observation provides Observation resources as defined in the FHIR STU3 release in real time.

Here are two examples of payload you can retrieve from this channel.

Simple
Composed
Simple
{
"category": [
{
"coding": [
{
"code": "vital-signs",
"display": "Vital Signs",
"system": "http://hl7.org/fhir/observation-category"
}
],
"text": "Vital Signs"
}
],
"code": {
"coding": [
{
"code": "8310-5",
"display": "body_temperature",
"system": "http://loinc.org"
}
],
"text": "Température"
},
"context": {
"reference": "863b08e6-601e-48ce-b71c-728421e16b95"
},
"device": {
"display": "thermometer",
"reference": "5d1a2fefa37f4d0017966643"
},
"effectiveDateTime": "2019-12-10T14:08:48.645Z",
"resourceType": "observation",
"status": "final",
"valueQuantity": {
"code": "C",
"system": "http://unitsofmeasure.org",
"unit": "C",
"value": 41.6
}
}
Composed
{
"category": [
{
"coding": [
{
"code": "vital-signs",
"display": "Vital Signs",
"system": "http://hl7.org/fhir/observation-category"
}
],
"text": "Vital Signs"
}
],
"code": {
"coding": [
{
"code": "blood_pressure",
"display": "blood_pressure",
"system": "http://loinc.org"
}
],
"text": "blood_pressure"
},
"component": [
{
"code": {
"coding": [
{
"code": "8480-6",
"display": "systolic_blood_pressure",
"system": "http://loinc.org"
}
]
},
"valueQuantity": {
"system": "http://unitsofmeasure.org",
"unit": "mmHg",
"value": 141
}
},
{
"code": {
"coding": [
{
"code": "8462-4",
"display": "diastolic_blood_pressure",
"system": "http://loinc.org"
}
]
},
"valueQuantity": {
"system": "http://unitsofmeasure.org",
"unit": "mmHg",
"value": 83
}
},
{
"code": {
"coding": [
{
"code": "8867-4",
"display": "heart_rate",
"system": "http://loinc.org"
}
]
},
"valueQuantity": {
"system": "http://unitsofmeasure.org",
"unit": "bpm",
"value": 75
}
}
],
"context": {
"reference": "08281fa8-d8f2-4cac-b46b-d9cd951058e9"
},
"device": {
"display": "blood_pressure_monitor",
"reference": "5c98c120184d54001718d5ce"
},
"effectiveDateTime": "2019-12-10T17:24:04.227Z",
"resourceType": "Observation",
"status": "final"
}

Depending on the device you are using the observation can look a bit different:

  • simple: When you use a simple device like a weight scale or a thermometer for instance, you will get only one simple measurement attached to the observation (e.g. weight for the scale or temperature for the thermometer). Therefore you can directly access the measurement in the valueQuantity property.

  • composed: When you use a pulse oximeter or a blood pressure monitor for instance, you will get two or three different kinds of measurements (e.g. heart rate and spO2 for the pulse oximeter or systolic, diastolic blood pressure for the blood pressure monitor). Therefore the measurements are gathered in the component property.

For more details on how to retrieve information from the payload please refer to the schema section.

Schema

Measurements use the Observation schema as defined in the FHIR STU3 release:

{
"resourceType" : "Observation",
// from Resource: id, meta, implicitRules, and language
// from DomainResource: text, contained, extension, and modifierExtension
"identifier" : [{ Identifier }], // Business Identifier for observation
"basedOn" : [{ Reference(CarePlan|DeviceRequest|ImmunizationRecommendation|
MedicationRequest|NutritionOrder|ProcedureRequest|ReferralRequest) }], // Fulfills plan, proposal or order
"status" : "<code>", // R! registered | preliminary | final | amended +
"category" : [{ CodeableConcept }], // Classification of type of observation
"code" : { CodeableConcept }, // R! Type of observation (code / type)
"subject" : { Reference(Patient|Group|Device|Location) }, // Who and/or what this is about
"context" : { Reference(Encounter|EpisodeOfCare) }, // Healthcare event during which this observation is made
// effective[x]: Clinically relevant time/time-period for observation. One of these 2:
"effectiveDateTime" : "<dateTime>",
"effectivePeriod" : { Period },
"issued" : "<instant>", // Date/Time this was made available
"performer" : [{ Reference(Practitioner|Organization|Patient|RelatedPerson) }], // Who is responsible for the observation
// value[x]: Actual result. One of these 11:
"valueQuantity" : { Quantity },
"valueCodeableConcept" : { CodeableConcept },
"valueString" : "<string>",
"valueBoolean" : <boolean>,
"valueRange" : { Range },
"valueRatio" : { Ratio },
"valueSampledData" : { SampledData },
"valueAttachment" : { Attachment },
"valueTime" : "<time>",
"valueDateTime" : "<dateTime>",
"valuePeriod" : { Period },
"dataAbsentReason" : { CodeableConcept }, // C? Why the result is missing
"interpretation" : { CodeableConcept }, // High, low, normal, etc.
"comment" : "<string>", // Comments about result
"bodySite" : { CodeableConcept }, // Observed body part
"method" : { CodeableConcept }, // How it was done
"specimen" : { Reference(Specimen) }, // Specimen used for this observation
"device" : { Reference(Device|DeviceMetric) }, // (Measurement) Device
"referenceRange" : [{ // Provides guide for interpretation
"low" : { Quantity(SimpleQuantity) }, // C? Low Range, if relevant
"high" : { Quantity(SimpleQuantity) }, // C? High Range, if relevant
"type" : { CodeableConcept }, // Reference range qualifier
"appliesTo" : [{ CodeableConcept }], // Reference range population
"age" : { Range }, // Applicable age range, if relevant
"text" : "<string>" // Text based reference range in an observation
}],
"related" : [{ // Resource related to this observation
"type" : "<code>", // has-member | derived-from | sequel-to | replaces | qualified-by | interfered-by
"target" : { Reference(Observation|QuestionnaireResponse|Sequence) } // R! Resource that is related to this one
}],
"component" : [{ // Component results
"code" : { CodeableConcept }, // R! Type of component observation (code / type)
// value[x]: Actual component result. One of these 10:
"valueQuantity" : { Quantity },
"valueCodeableConcept" : { CodeableConcept },
"valueString" : "<string>",
"valueRange" : { Range },
"valueRatio" : { Ratio },
"valueSampledData" : { SampledData },
"valueAttachment" : { Attachment },
"valueTime" : "<time>",
"valueDateTime" : "<dateTime>",
"valuePeriod" : { Period },
"dataAbsentReason" : { CodeableConcept }, // C? Why the component result is missing
"interpretation" : { CodeableConcept }, // High, low, normal, etc.
"referenceRange" : [{ Content as for Observation.referenceRange }] // Provides guide for interpretation of component result
}]
}

Here are some of the noticeable properties:

property

description

valueQuantity

valueQuantity.system

defines the system defining the previous code

i.e. https://loinc.org/

valueQuantity.unit

defines the unit in which the quantity is expressed

i.e. C for a body temperature

valueQuantity.value

defines the actual value of the quantity i.e. 37 for a body temperature

device

device.reference

defines the id of the device used to take the measurement

i.e. 5d1a2fefa37f4d0017966643

device.display

defines the type of device used to take the measurement

i.e. thermometer

effectiveDateTime

represents the time at which the measurement was taken

i.e. 2019-12-10T14:08:48.645Z

code

code.coding

describes what the measure is and how we can reference it in a specific system.

code.coding.code

describes the code used to define the measurement

i.e. 8310-5

code.coding.system

defines the system related to the code

i.e. http://loinc.org

code.coding.display

a human readable version of the code

Receiving events from Kligo

Here is an example for listening to Observation using a simple web socket javascript client:

JavaScript
JavaScript
const ws = new WebSocket("ws://localhost:63336/v3/Observation");
ws.onopen = function open() {
console.log("opened");
setConnected(true);
};
ws.onclose = function close() {
console.log("closed");
setConnected(false);
};
ws.onmessage = function data(event) {
const observation = JSON.parse(event.data);
console.log(observation);
};

A working version of this example can be found here.