|Subject:||Re: [Health-dev] GNU Health User at Savannah - development team|
|Date:||Fri, 19 Sep 2014 12:49:15 +0200|
I'm responding directly to the health-dev mailing list, to make sure
that anyone interested in this topic (hi Andrew!) can jump in.
2014-09-11 16:56 GMT+02:00 Vittorio Meloni <address@hidden>:
> Thank you Louis and hello Chris and Emilien.
> I introduce my colleague Alessandro which is one of the main developer of
> the module.
> I had the pleasure to "meet" Emilien via email, when I first introduced our
> hl7 python API to the mailing list and I also saw his thorough presentation
> of HL7 and python-hl7 library.
> As Luis told you, we're implementing a PDQ module for GNU Health. PDQ
> (Patient Demographics Query) is one of the most popular IHE profiles and it
> aims to allow system to retrieve patients' demographics.
Starting with patient demographics is indeed smart.
Although I am not yet familiar with the PDQ profile, I see that it is
pointing to amongs other chapter 3 of the HL7 v2.5 specs . I have
implemented and help support "regular" HL7v2 QRY^A19 at a number of
Dutch hospitals, so that shouldn't be too different from what I'm used
Another very similar message type is the ADT outgoing interface (the
response on the query is basically the same as an A08 update message),
it should be pretty easy to support that as well.
> We're implementing it to be extensible to other IHE or HL7 transactions in
> the future. This module will be a separated process from Tryton and it's
> based on SocketServer.
> As I wrote in the previous email, we're trying to keep the implementation as
> integrated as possible to Tryton , so we're keeping the configuration of the
> module integrated with the same configuration method and files of Tryton
> itself adding some legal options to the configuration file.
> Let me know your thoughts.
I'm responding further down, after your description of the way you
plan to implement this.
At the end, I will be sharing my ideal vision for such a module.
In my opinion, this is not an optimal design. I would like to see this
> Luis, I haven't understood what you mean with "parent directory": do you
> mean at the same level as tryton and misc or as child of tryton directory?
> 2014-09-11 12:13 GMT+02:00 Luis Falcon <address@hidden>:
>> Dear Vittorio
>> Let me introduce you to Chris Zimmerman and Emilien Klein. Chris is
>> working on the implementation of both the server and the client for
>> HL7 FHIR. Emilien is a long time supporter of integrating HL7 in GNU
>> Health. He has done a cool video / presentation on HL7 plans for GNU
>> Vittorio and his team are focusing on HL7 PDQ - correct me if I'm
>> I think is great you three know each other and share ideas and work.
>> As far as the directory structure in Savannah, I think the best is to
>> create a parent directory called "HL7" and from there put all the
>> related projects .
>> Let me know your thoughts.
>> On Tue, 9 Sep 2014 17:01:34 +0200
>> Vittorio Meloni <address@hidden> wrote:
>> > Thank you very much, Luis.
>> > I'll try to explain how we're implementing the module and especially
>> > how we're integrating it in GNU Health, so that you can tell me if
>> > you think it's a correct way to proceed, then I will insert a ticket
>> > in Savannah. Since, of course, we cannot access the tryton
>> > executable, we developed the hl7 server as an external process which
>> > accepts the MLLP request on a different port.
"interface" module (naming it broadly, to support potentially more
than just HL7) as an integral Tryton module.
>> > This executable is configurable using some parameters added to the
>> > tryton configuration file, for example listening host and port. The
>> > idea is that when a user wants to customize the parameters he/she can
>> > insert them in the tryton configuration file.
>> > About the query in the database, we used the python-sql module since
>> > we found in the GNU Health source some examples using it.
Using an external executable that queries the database directly
instead of going through Tryton/GNU Health doesn't seem optimal to me.
Using this approach is basically not different than what I understood
from Luis  is currently done at organizations that want to exchange
HL7 data: use Mirth as an interface engine, as it has the ability to
perform SQL queries and format the result into HL7. You would
basically be re-programming in an external application what others
have already implemented in Mirth. In that case, it would make more
sense to consolidate Mirth configurations, so that it can be shared
Also, by querying the database directly, you would have to closely
keep track of the database structure, and risk breaking the interface
if a change is made to the data model. Doing that in an external
binary is less robust that if you have a well defined API to access
>> > If you think it's ok we can continue implementing this way.
>> > Then we think that we need to put our library in the dependencies, so
>> > during the installation process it should install it from PyPi.
>> > Finally just a quick question: since it is not a classic Tryton module
>> > we're implementing, where do you think it should be put in the source
>> > tree? We're thinking to put it with the other modules anyway (e.g
>> > health/tryton/health_hl7).
>> > Hope it's ok,
>> > thank you and best.
>> > Vittorio
So, now that I've told you that I don't share your vision (sorry about
that ;)), let me share my ideal vision with you.
This applies regardless of the standard used to exchange information
(HL7 v2, HL7 v3, HL7 FHIR, others), but I'll use HL7v2 examples, as
that is the most frequently used standard *within* hospitals (I'm
seeing mostly HL7 v2.4). I see basically 3 types of interfaces:
- Outgoing interfaces:
Something happens in GNU Health (let's call that a trigger) that
needs to be communicated with downstream systems. Example include
(assuming that GNU Health is the source of truth for patient
demographics and ADT [Admission/Discharge/Transfer] information, and
the order placer system):
* new patient is created (generates an HL7 ADT A04 or A28 message)
* patient's address changed (generates an HL7 ADT A08 [update] message)
* patient is admitted to the hospital (generates an HL7 ADT A01 message)
* orders (lab, radiology, medication, etc.) are placed for a
patient (generates an HL7 ORM message [RDE for medication])
- Incoming interfaces (assuming demographics information is kept in
another system, and the laboratory sends result messages to GNU
* new patient is created (receive an HL7 ADT A04 or A28 message)
* patient's address changed (receive an HL7 ADT A08 [update] message)
* patient is admitted to the hospital (receive an HL7 ADT A01 message)
* results are made available for a patient (receive an HL7 ORU message)
- Bidirectional interfaces (again assuming GNU Health is the source of
truth for patient demographics):
* an external system queries GNU Health for patient demographics,
and the response to that query is sent in the acknowledgment ACK
message (all messages in HL7 are replied to by an ACK message, but in
case of a query the ACK contains a payload next to the technical
acknowledgement of reception of the message)
Disclaimer: what follows is rather similar to the interface framework
used at my day job, but my intent is not to describe that. Rather,
it's based on the best practices I have learned over the years,
working with a diverse range of systems: lab, pharmacy, radiology,
nuclear medicine med preparation, scheduling, specialty [ECG,
ophthalmology], vitals measuring devices, document management systems.
All these systems have variations around the same following concepts:
I imagine a Tryton module (at the same level as all other GNU Health
modules) that would perform a number of tasks:
- Allow for configuration of the interfaces, i.e. configuration
parameters that allow per-interface customization (e.g. one
organization wants to send the social security number of the patient
in PID-19, while the other doesn't want that information sent out) and
- IP adress/port configuration
- Allow to indicate which events should generate messages, and which
shouldn't (don't send temporary patient moves at this organization,
but do send them at that other)
- Allow to start/stop message, send email messages if interfaces are
unexpectedly stopped, or if messages haven't been received in a
specified amount of time (you'd obviously want to set that up only on
- Process messages in 2 distinct stages:
* One process takes care of sending (for outgoing) or receiving
(for incoming) the actual HL7 message. This process also handles the
ACK message: for outgoing messages, if the ACK didn't contain the code
AA (Application Accept), log an error that can be reviewed later. For
incoming messages, send an ACK message to indicate that the message
was properly received (just always send AA, even if the message
couldn't be processed later. we'll handle errors separately).
Processed messages get saved in the database, for later review or
* One process handles the interpretation of the message: building
the outgoing message from the database content, based on which event
was triggered, or filing the information received in the incoming
message to the database.
This is how the 2-stage processing would work:
* For outgoing interfaces, each time a trigger is hit, keep it in
a queue for later processing (useful if the interface has to be shut
down temporarily). Then another process goes through this list of
events one by one, and creates an HL7 message corresponding to the
event, before finally removing the event from the queue. The data is
retrieved from the database, but through an abstraction layer (e.g. a
getPatientName() function, instead of directly a SELECT statement).
* For incoming interfaces, receive the HL7 message and put it on a
queue (useful if you need to temporarily stop processing incoming
* For bidirectional interfaces, there wouldn't really be 2 stages,
as these are real-time interfaces. The process receiving the query is
also responsible to send the If it's down, you don't get a response,
so you'll need to send your query again.
The reason for 2-stage processing is that it separates processing of
the message content and the communication with external parties, which
allows to adequately process temporary spikes. You wouldn't want to
drop e.g. incoming results messages, just because you're still
processing the previous message.
A translation mechanism must be provided, which allow to send values
in the messages that might be different that the values used in GNU
Health itself. For example a lab procedure for Kalium would have the
code K in GNU Health, but KAL in the performing lab system. The
external code could be a property of the procedure itself (saved in
the database directly), but a
manner to do these mappings is a simple 2-column table.
Of course, errors can happen. e.g. an incoming message comes in with a
patient ID that is unknown, or for a lab procedure code that isn't
recognized. Or an outgoing message must be generated, but some needed
information isn't there (e.g. code of a department, or lab procedure).
We'll need an error database, that would log the situation and link
the error to the received message.
The interface module would allow to search for messages based on
configurable parameters (e.g. show me all messages for this patient on
that interface for period X, or all lab orders for procedure Y), and
make it possible to manually edit, reprocess (incoming) or regenerate
(outgoing) messages. This is useful when a message couldn't be
processed (e.g. incorrect patient ID), the cause for the issue has
been fixed, and the message can now be processed correctly.
This is a golden opportunity to implement the base of the system in a
way that will make developing new interfaces easily in the future,
independant of the actual communications standard used. Otherwise,
we'll get inconsistency: an HL7 FHIR module here, an IHE PDQ
executable there, direct database-reading by Mirth for these other
places. And the day that somebody wants to receive appointment
information, we'll have to think about yet another way of doing things
I'm interested in what your thoughts are.
|[Prev in Thread]||Current Thread||[Next in Thread]|