Implantable device list - 2015 ONC MU3 a14

I am assuming the clinical aspects / diagnostics etc. are left part (1) of the 1:m relationship to devices. Someone may need 3 pacemakers over their life without any changes to ‘Issue’.

Hi,
I’d rec a separate Issue category (Implantable Devices;implantable_devices), which will work nicely for clinical flow and be a nice container for the entry. In the case with 3 different pacemakers, note each will have their own UID and would be separate entries (with the 2 removed ones being set to be Final or something equivalent). Note agree the ordering/querying of the device belongs in procedures, but I think the actual existence of the device should be stored in the new Issue category.
-brady

Perhaps if it is the user/provider performing device procedure. I’m not sure how a device is selected or ordered however, the procedure would become part of an ongoing encounter thread. The procedure itself would be selected from the practices custom compendium however that compendium item is designed. It may or may not have device info and because OpenEMR doesn’t control what that procedure looks like, we would never be assured the device is correctly tracked as part of patient history unless the device is recorded elsewhere.

This I would agree is best design. Having a separate form to record device where it is readily part of patient issues/history or attached to encounter history if needed. I only differ by naming the form Medical Devices because i’m thinking there could be wearable devices that are prescribed (A1c comes to mind). Hmm, are devices ordered via a prescription?

Anyway, i’m an engineer who relies on deductive reasoning and logic and not clinical experienced so correcting me if needed is appreciated.

Also it would behoove us to research how patient devices are transmitted in such as CCDA Continuity of Care Transfer of Care or Care Summary and especially FHIR for import by other EHRs and a look see at our import. This I will take as an action item and report back.

Lastly, I feel a closer look at how this is tested in certification can provide some clarity. A repost url to testing.
https://www.healthit.gov/test-method/implantable-device-list

Hi @RachelEllison
I hope we are of some help in your endeavor. Ultimately, it is your project and how to proceed with the design is up to you . Just know you have resources in the community to help if needed.
Jerry

Sorry missed this key requirement which is very limited to just entering device data. We have ongoing issue about storing and analyzing output data streams from some devices so went off on tangent. When a new entity comes up, we defer to hl7v3 since our requirements usually are a tiny part of their solutions. Relevant section for medical devices shows superset of attributes needed. You can use json viewers like this to copy+paste json and see specific fields with their meaning. As you see this has little or no overlap to issues/lists.

For what it is worth, we implemented this some time ago (in a very elemental form) using a ‘Devices’ transaction record leveraging the LBT code. That approach will probably meet the MU requirements(?). Today we would probably use json focused device and device-udi parent child structure still with patient transactions as entry point for users.

Best.

You mentioned CouchDB, is there some interest in migrating to that? A student is working on LOINC mapping and is having a hard time with figuring out how to map data into tables when the data has an inherent tree-like structure.

Another thing to note that of the 3 issuing agencies use different date/time formats for their dates(manufacturing/production date and expiration date). https://www.gnu.org/software/pspp/manual/html_node/Time-and-Date-Formats.html

GSI uses only [YYMMDD] e.g 200201 for February 1st 2020.

HIBCC can use [YYJJJ],[YYJJJHH],[YYYMMDD],[MMYY][MMDDYY][YYMMDDHH]

And ICCBA does [YYYJJJ] only(where JJJ is julian date, which means what day of the year it is. e.g February 2nd 2020 is 020033.

Does OpenEMR have an already integrated datetime conversion package? I’m not looking forward figuring out how to wrangle all those different standards. Is there a preferred format for dates/times in the OpenEMR database?

Thanks,

Current codebase optionally supports couchdb only for documents as an alternative to storing those files on server filesystem. I referenced Couchdb in context of storing loosely formatted data streams emitted by various devices. Couchdb, a noSQL database, is not an general option for this SQL based project.

Good news is @sunsetsystems already took care of importing LOINC compendiums in proc orders. I have not looked at recent code but you cheat by setting up a hard coded vendor and import a file to establish the tree structure of 1000s of testing items. Several community members should be able to help in that area.

mysql requires SQL statements provide dates in YYYY-MM-DD format. There are standard php or javascript functions that map some of the formats based on user preferences for display purposes. Standard Date classes in php or Javascript would handle any other conversions.

1 Like

Looks like the below PHP function can do URL encoding.

https://www.php.net/manual/en/function.urlencode.php

2 Likes

So here is my code so far:

<?php //This allows you to access/run your code without being logged into OpenEMR. //Good for testing and development but should be set to true before releasing into the public codebase. $ignoreAuth = true; /**Globals.php is located in the openemr/interface folder. * It contains some important code and you'll need to give the path to the file in the parenthesis and double quotes below. * The ../ means go up one folder. Since we used it 3 times that tells the code to look 3 folders up for globals.php * If we made a sub folder in the current folder holding this code and moved it there, you'd need another ../ if you moved this code up a folder * you'd need one fewer ../ */ require_once("../../../globals.php"); //This tells the code to use the OpenEMR header with the menu options. use OpenEMR\Core\Header; //If your code calls another php script or redirects there you'll want to uncomment out the below and send a token in the command line. //A token can only be used once. This is used to keep OpenEMR data safe from a cross site scripting attack. /* if (!empty($_REQUEST)) { if (!verifyCsrfToken($_REQUEST["csrf_token_form"])) { csrfNotVerified(); } } */ //Collect data from page launched by. //$pid is the variable name. //It checks to see if it's set. If yes, it sets it to the value on the right. if(isset($_REQUEST['pid'])){ $pid = $_REQUEST['pid']; }else{ $pid = 'Not Set'; } //check if implantable device is associated with a procedure if(isset($_REQUEST['procedure'])){ $procedure = $_REQUEST['procedure']; }else{ $procedure = 'Not Set'; } //end PHP header ?> Implantable Device Parser
<?php
// Auto pulls in needed dependencies jquery, bootstrap, theme etc.
Header::setupHeader(['datetime-picker']);
?>

<?PHP
    $DI = $_POST['DeviceIdentifier'];
    //print($DI);
    //example DI from GS1:  (01)51022222233336(11)141231(17)150707(10)A213B1(21)1234
    $UDI= urlencode($DI);
    echo $UDI; 
?>
<FORM NAME ="form1" METHOD ="POST" ACTION = "GUDID.php">
    <INPUT TYPE = "Text" VALUE ="" NAME = "DeviceIdentifier">
    <INPUT TYPE = "Submit" Name = "Submit1" VALUE = "Parse ID">
</FORM>

So for right now what it does is collect the UDI from the text field, convert to URL encoding and display it to the user.
Our example of: (01)51022222233336(11)141231(17)150707(10)A213B1(21)1234
becomes: %2801%2951022222233336%2811%29141231%2817%29150707%2810%29A213B1%2821%291234

Up next we’ll try to use the FDA AccessGUDID Parse UDI API:
https://accessgudid.nlm.nih.gov/resources/developers/parse_udi_api

It can provide the response in either json or xml.

I think I’ll give this method a try since it gives options for both a json or xml response.

1 Like

Continuing to add to the PHP in the head block of the HTML code, let’s make an API call.

$apiCall=‘https://accessgudid.nlm.nih.gov/api/v2/parse_udi.json?udi=’ . $UDI;

echo $apiCall;

This returns:
https://accessgudid.nlm.nih.gov/api/v2/parse_udi.json?udi=(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234

$response = file_get_contents($apiCall);
echo $response;

This returns:
{“udi”:"(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234",“issuingAgency”:“GS1”,“di”:“51022222233336”,“manufacturingDateOriginal”:“141231”,“manufacturingDateOriginalFormat”:“YYMMDD”,“manufacturingDate”:“2014-12-31”,“expirationDateOriginal”:“150707”,“expirationDateOriginalFormat”:“YYMMDD”,“expirationDate”:“2015-07-07”,“lotNumber”:“A213B1”,“serialNumber”:“1234”}

1 Like

So let’s take a look at the json the api returns using json_decode:
https://www.php.net/manual/en/function.json-decode.php

var_dump(json_decode($response));

returns:

stringobject(stdClass)#316 (11) { [“udi”]=> string(56) “(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234” [“issuingAgency”]=> string(3) “GS1” [“di”]=> string(14) “51022222233336” [“manufacturingDateOriginal”]=> string(6) “141231” [“manufacturingDateOriginalFormat”]=> string(6) “YYMMDD” [“manufacturingDate”]=> string(10) “2014-12-31” [“expirationDateOriginal”]=> string(6) “150707” [“expirationDateOriginalFormat”]=> string(6) “YYMMDD” [“expirationDate”]=> string(10) “2015-07-07” [“lotNumber”]=> string(6) “A213B1” [“serialNumber”]=> string(4) “1234” }

To assign it to a variable you’ll want to put the true argument in after the data.

$Parsed = json_decode($response, true);

Now we can index the response by field name.

echo $Parsed[“udi”];
(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234

echo $Parsed[“expirationDate”];
2015-07-07

1 Like

Now let’s take a look at the device lookup API.

It can also return the data in json or xml format.

It can take in as input the full Universal Device Identifier(UDI) in the above example (01)51022222233336(11)141231(17)150707(10)A213B1(21)1234

Or the DI, or Device Identifier string. 51022222233336 in the above example.

However the string must be put percent/url encoded. I think for the device identifier it should just be alphanumeric characters.

For a UDI API request it should look like this:
https://accessgudid.nlm.nih.gov/api/v2/devices/lookup.json?udi=(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234

For a DI API request it should be:
https://accessgudid.nlm.nih.gov/api/v2/devices/lookup.json?di=51022222233336

We’ll need to decide what information to collect store locally. My initial thoughts are the sterilization method and contact fields. Also MRI safety information. If a person has a device with MRI concerns we’ll want to put that on the dashboard for sure.

However instead of pulling out all the device information and making it look pretty, we can also just create a link that directs the clinician to the device information page.

For example a device with DI D0470046351
The below link sends you to the GUDID site with a nice GUI.
https://accessgudid.nlm.nih.gov/devices/D0470046351

Let’s generate this link in PHP. We’ll need to make a string with this format:
link text

But since we’re going to be appending strings within strings you’ll need to make sure you escape the double quotes you want to keep without.
http://www.hackingwithphp.com/2/6/2/escape-sequences

$DevicePage= “<a href=“https://accessgudid.nlm.nih.gov/devices/” . $Parsed[“di”] . “”>Visit Access GUDID Device Information Page”;

echo $DevicePage

This creates a link that says:
Visit Access GUDID Device Information Page
and sends you to
https://accessgudid.nlm.nih.gov/devices/51022222233336

Which isn’t a real medical device but if it were that should work.

So I know it doesn’t appear to be mandated by the standard but let’s go ahead and add a field for tracking where in the body the device is implanted. Since each clinic will likely have their own top n implantatation sites that will vary based on services provider, let’s use the Manage Lists tool to allow them to customize what body parts list by default.

First let’s take a look at the surgery issue list. Navigate to Administration -> Lists

Next Procedure Body Sites

Procedure Lateralities

Procedure Routes

One thing to consider is that the guidance says that an implantable device should be associated with a procedure. But at least with how the system appears to handle things now, the surgery issue list contains the types of procedures, like appendectomy, tonsilectomy, etc.

The location, laterality, and routes are listed under the name procedure.

But what about nonsurgical procedures? Like the Epley Maneuver? Could we maybe change the surgery issue list to procedure issue list and have both stored in the same table?

Let’s consider an example. Cochlear implants.
The body site might be considered “ear” or something more specific.

The laterality for the procedure might be left, right, or both(bilateral).
Then again if you need to know which serial number is in which ear it might necessitate coding as two separate procedures or listing multiple implantations in the same procedure/surgery window.

The procedure route would be surgical

The Surgical issue would be Cochlear Device implantation with CPT code 69930.

At some point the implant would need to be removed(explanted) or replaced (explant followed by implant)
These appear to have separate codes.
https://www.supercoder.com/coding-newsletters/my-otolaryngology-coding-alert/reader-question-implant-unlisted-code-applicability-for-cochlear-device-removal-108884-article

So perhaps when allowing the clinician to record a surgery/procedure there should be the option to remove an existing implanted device and implant new device(s) at the same time. Making sure that they have independently recorded locations and lateralities.

To get all listed issues recorded in the columns above you’ll want to run the below SQL commands.
SELECT title FROM list_options WHERE list_id = ‘surgery_issue_list’;

SELECT title FROM list_options WHERE list_id = ‘proc_body_site’;

SELECT title FROM list_options WHERE list_id = ‘proc_route’;

SELECT title FROM list_options WHERE list_id = ‘proc_lat’;

However if you only want to grab the active ones, you 'll want to add an additional check as seen below.

SELECT title FROM list_options WHERE list_id = ‘surgery_issue_list’ AND activity =1;

While using the title field to get the “pretty” text to display in the GUI I’d recommend also grabbing the option id like below to use to reference in your code.
SELECT option_id FROM list_options WHERE list_id = ‘surgery_issue_list’ AND activity =1;

Let’s make a first pass at making an ImplantableDevice Table. In PHPmyadmin click the openemr database on the left navigation pane. Scroll to the bottom of the page, Type a name in the box and click create new table with 21 columns.


Under index, set primary for the ID row, this will be a unique number given to each implanted device to be used throughout the codebase.

Click preview SQL to get the below.

CREATE TABLE openemr.ImplantableDevices(IDINT NOT NULL ,PIDINT NOT NULL ,DeviceTitleVARCHAR NOT NULL ,DeviceDescriptionTEXT NOT NULL ,ImplantDateDATE NOT NULL ,ExplantDateINT NOT NULL ,DeviceIdentifierVARCHAR NOT NULL ,UDIVARCHAR NOT NULL ,IssuingAgencyVARCHAR NOT NULL ,ExpirationDateVARCHAR NOT NULL ,SerialNumberVARCHAR NOT NULL ,MRI_Safety_InformationTEXT NOT NULL ,DevicePackagedAsSterileVARCHAR NOT NULL ,RequiresSterilizationBeforeUseVARCHAR NOT NULL ,SterilizationMethodsTEXT NOT NULL ,StorageAndHandlingNotesTEXT NOT NULL ,ContactPhoneVARCHAR NOT NULL ,ContactEmailVARCHAR NOT NULL ,AssociatedProceduresVARCHAR NOT NULL ,AssociatedSurgeriesINT NOT NULL ,Comments TEXT NOT NULL , PRIMARY KEY (ID)) ENGINE = InnoDB;

Hit save to get your new table.

First, let’s take a look at device expiration dates.

Here’s what an example GS1 UDI Parsing API returns:
{“udi”:"(01)51022222233336(11)141231(17)150707(10)A213B1(21)1234",“issuingAgency”:“GS1”,“di”:“51022222233336”,“manufacturingDateOriginal”:“141231”,“manufacturingDateOriginalFormat”:“YYMMDD”,“manufacturingDate”:“2014-12-31”,“expirationDateOriginal”:“150707”,“expirationDateOriginalFormat”:“YYMMDD”,“expirationDate”:“2015-07-07”,“lotNumber”:“A213B1”,“serialNumber”:“1234”}

We know that the database wants dates in format YYYY-MM-DD. Let’s take a look at the other issuing agency formats.

And here’s an example HIBCC:

{
"udi":"+H123PARTNO1234567890120/$$420020216LOT123456789012345/SXYZ456789012345678/16D20130202C",
"issuingAgency":"HIBCC",
"di":"H123PARTNO1234567890120",
"expirationDateOriginalFormat":"YYMMDDHH",
"expirationDateOriginal":"20020216",
"expirationDate":"2020-02-02",
"lotNumber":"LOT123456789012345",
"serialNumber":"XYZ456789012345678",
"manufacturingDateOriginalFormat":"YYYYMMDD",
"manufacturingDateOriginal":"20130202",
"manufacturingDate":"2013-02-02"
}

Here’s what ICCBBA returns:

{
"udi":"=/A9999XYZ100T0944=,000025=A99971312345600=\u003e014032=}013032\u0026,1000000000000XYZ123",
"issuingAgency":"ICCBBA",
"di":"A9999XYZ100T0944",
"serialNumber":"000025",
"donationId":"A99971312345600",
"expirationDateOriginalFormat":"YYYJJJ",
"expirationDateOriginal":"014032",
"expirationDate":"2014-02-01",
"manufacturingDateOriginalFormat":"YYYJJJ",
"manufacturingDateOriginal":"013032",
"manufacturingDate":"2013-02-01",
"lotNumber":"000000000000XYZ123"
}

So it looks like the API handles converting the original date time formats to one that’s acceptable to the MySQL database. So in theory all we should need to do is grab the expirationDate field.

In addition to MRI safety information the API returns additional information regarding natural rubber latex, or NRL, which is a common allergy.

Here’s a snippet of what the device_lookup v2 api json returns.

labeledContainsNRL: false,
labeledNoNRL: false,
MRISafetyStatus: “MR Conditional”,

I’d like to create a warning that pops up if a clinician tries to add an implantable device made or packaged with NRL to a person known to have a latex allergy.

A latex allergy isn’t one of the four included in the add/edit allergy issue page by default.

One can query the lists table for patient pid=?, activity=1, type=allergy, title=latex to capture hand typed documented allergies. It doesn’t appear to be case sensitive but this will not take into account things like shorthand, misspellings, other languages, alternate names like NRL, etc.

One thing we could do is add it to the list_options table.

As for how to handle the default latex allergy coding:
https://www.icd10monitor.com/coding-of-allergies-presents-unique-challenges

It would appear that the ICD10 code for latex allergy is Z91:040

To add this as an option via a SQL query, we should be able to use the below:

INSERT INTO list_options (list_id, option_id, title, seq, is_default, option_value, mapping, notes, codes, toggle_setting_1, toggle_setting_2, activity, subtype, edit_options, timestamp) VALUES (‘allergy_issue_list’, ‘latex’, ‘Latex’, ‘0’, ‘0’, ‘0’, ‘’, NULL, ‘ICD10:Z91.040’, ‘0’, ‘0’, ‘1’, ‘’, ‘1’, CURRENT_TIMESTAMP)

hi @RachelEllison ,

Here’s where you can add this to database.sql:
openemr/database.sql at master · openemr/openemr · GitHub

We are also in luck on the translation front. Note that the title of the allergy (in this case Latex, which is taken from title in list_options) is stored in title in lists:

And the option_id from list_options entry (in this case latex) is then stored in the list_option_id of in lists:

So searching for latex in list_option_id of lists is going to work for all languages. Also good to store the ICD10 code as you do.

Hi @RachelEllison @Rachel_Ellison (which is it:))
Implantable Device is a part of the U.S FHIR Core required by ONC. So we are starting to consider inclusion to both our standard and FHIR API.
Is there somethings our FHIR team can help with to move this along. Looks like you are close with the infrasture, can we help with integration?

Hi Jerry, here’s some code I had been messing around with if that helps.

1 Like